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

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

[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
From: "Vasco Alexandre da Silva Costa" <vasc@xxxxxxxxxxxxxx>
Date: Sun, 16 May 2004 10:42:55 -0700
Reply-to: rt@xxxxxxxxxxx

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

We have long wanted to have more configurable rulesets. At first, this
desire arose when someone wished to add a SMAC mode for Freeciv.

The current building effects are hardcoded. This is not very different
from how the commercial Civs do it, but this makes it impossible for a
modpack author to make even minor changes to the buildings unless he can
program in C.

This patch allows more configurable effects. The premises around its
design are:

* the original design for effects is sound, it just needs to be
  generalized, instead of hard-coded.
* there should be no global updates each time any effect is
  activated. only affected things should be updated. otherwise the code
  will scale poorly with a great number of effects.
* minimum memory and network bandwidth usage.
* encapsulated design; in order for future code modifications to be
  easy.

The patches:
* 'vector.diff' contains code for desirable vector functionality.
* 'effects.diff' contains code for the effects code.
* 'implement.diff' contains code for implementing a couple of effects,
  so you can get a better idea of how this will work in practice.

For more information on how the code works, please refer to
'common/eff.c' in the 'effects.diff' patch.

There you will also find a comment discussing how to generalize this
code further. The encapsulation makes this easier.

'effects.diff' and 'implement.diff' are larger than they could be
because they reimplement the ruleset effect format.

The pre-existing format is currently unused, but the code still remains
there.

For info on the game rules of Sid Meyer 4X games see:
http://www.freeciv.org/~vas/wiki/index.php/Generalization

You may find some interesting information in there.

Thanks for reading,
-vasc

diff -Nurd -X freeciv/diff_ignore freecvs/utility/specvec.h 
freeciv/utility/specvec.h
--- freecvs/utility/specvec.h   2004-05-15 01:48:17.000000000 +0100
+++ freeciv/utility/specvec.h   2004-05-15 04:15:59.000000000 +0100
@@ -106,11 +106,18 @@
 static inline SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (SPECVEC_VECTOR *tthis,
                                                      int index)
 {
-  if (index < 0 || index >= tthis->size) {
-    assert(index >= 0 && index < tthis->size);
-    return NULL;
+  if (index == -1) {
+    if (tthis->size > 0) {
+      return tthis->p + tthis->size - 1;
+    } else {
+      return NULL;
+    }
   } else {
-    return tthis->p + index;
+    if (index < 0 || index >= tthis->size) {
+      return NULL;
+    } else {
+      return tthis->p + index;
+    }
   }
 }
 
@@ -130,6 +137,27 @@
   SPECVEC_FOO(_vector_init)(tthis);
 }
 
+static inline void SPECVEC_FOO(_vector_insert_back) (SPECVEC_VECTOR *tthis,
+                                                    SPECVEC_TYPE *pfoo)
+{
+  const size_t last = tthis->size;
+
+  SPECVEC_FOO(_vector_reserve) (tthis, last + 1);
+  tthis->p[last] = *pfoo;
+}
+
+
+
+#define TYPED_VECTOR_ITERATE(atype, vector, var) {      \
+  int myiter;                                          \
+  atype *var;                                           \
+  for (myiter = 0; myiter < (vector)->size; myiter++) { \
+    var = &(vector)->p[myiter];                                \
+ 
+/* Balance for above: */
+#define VECTOR_ITERATE_END  }}
+
+
 #undef SPECVEC_TAG
 #undef SPECVEC_TYPE
 #undef SPECVEC_PASTE_
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.208
diff -u -r1.208 city.c
--- common/city.c       6 May 2004 21:28:03 -0000       1.208
+++ common/city.c       16 May 2004 17:18:09 -0000
@@ -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 */
 
@@ -476,8 +477,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)) {
@@ -491,13 +492,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)) {
@@ -516,6 +517,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)) {
@@ -539,12 +541,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) {
@@ -620,6 +617,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)) {
@@ -652,14 +650,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) {
@@ -734,6 +726,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
@@ -772,9 +765,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);
@@ -1029,11 +1020,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) {
@@ -1604,23 +1595,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));
 }
 
 /**************************************************************************
@@ -1629,19 +1604,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));
 }
 
 /**************************************************************************
@@ -1675,23 +1638,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;
   }
@@ -1949,21 +1899,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_local(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) {
@@ -1993,14 +1933,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_global(pcity, EFT_MAKE_HAPPY)) > 0) {
+    bonus += mod;
+
     while (bonus > 0 && pcity->ppl_content[4] > 0) {
       pcity->ppl_content[4]--;
       pcity->ppl_happy[4]++;
@@ -2009,10 +1948,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_global(pcity, EFT_MAKE_CONTENT);
+
   /* get rid of angry first, then make unhappy content */
   while (bonus > 0 && pcity->ppl_angry[4] > 0) {
     pcity->ppl_angry[4]--;
@@ -2024,6 +1962,7 @@
     pcity->ppl_content[4]++;
     bonus--;
   }
+
   if (city_affected_by_wonder(pcity, B_SHAKESPEARE)) {
     pcity->ppl_content[4] += pcity->ppl_unhappy[4] + pcity->ppl_angry[4];
     pcity->ppl_unhappy[4] = 0;
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.209
diff -u -r1.209 unit.c
--- common/unit.c       6 May 2004 21:28:03 -0000       1.209
+++ common/unit.c       16 May 2004 17:18:16 -0000
@@ -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;
     }
Index: data/default/buildings.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/buildings.ruleset,v
retrieving revision 1.45
diff -u -r1.45 buildings.ruleset
--- data/default/buildings.ruleset      13 May 2004 18:17:37 -0000      1.45
+++ data/default/buildings.ruleset      16 May 2004 17:18:17 -0000
@@ -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"
+      "Make_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"
+      "Make_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
@@ -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"
@@ -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"
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.310
diff -u -r1.310 plrhand.c
--- server/plrhand.c    11 May 2004 17:59:34 -0000      1.310
+++ server/plrhand.c    16 May 2004 17:18:22 -0000
@@ -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);
-
-         do_free_cost(pplayer);
-         found_new_tech(pplayer, i, FALSE, FALSE, A_NONE);
-         break;
-       }
-      } tech_type_iterate_end;
-    }
+  int mod;
+
+  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 freeciv/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-16 17:44:01.482382080 +0100
@@ -0,0 +1,989 @@
+/**********************************************************************
+ 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_bonus
+
+  * get_city_bonus
+    * get_city_bonus_improvs   ; should be possible to eliminate these funcs.
+    * get_city_bonus_wonders
+
+  * 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_insert_back(&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_insert_back(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)
+{
+  switch (eff->type) {
+    case REQ_NONE:
+      operate(eff->op, power, eff->value);
+      break;
+    case REQ_TECH:
+      if (player_knows_tech(plr, eff->req.tech)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_GOV:
+      if (get_gov_pplayer(plr) == eff->req.gov) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    default:
+      freelog(LOG_ERROR, "player_power_func: %d", eff->type);
+      break;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_power_func(struct city *pcity, struct effect *eff,
+                                  int *power)
+{
+  switch (eff->type) {
+    case REQ_NONE:
+      operate(eff->op, power, eff->value);
+      break;
+    case REQ_TECH:
+      if (player_knows_tech(city_owner(pcity), eff->req.tech)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_GOV:
+      if (get_gov_pcity(pcity) == eff->req.gov) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_BUILDING:
+      if (city_got_building(pcity, eff->req.building)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_WONDER:
+      if (city_affected_by_wonder(pcity, eff->req.wonder)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    default:
+      freelog(LOG_ERROR, "city_power_func: %d", eff->type);
+      break;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_building_power_func(struct city *pcity,
+                                           Impr_Type_id id,
+                                           struct effect *eff, int *power)
+{
+  switch (eff->type) {
+    case REQ_NONE:
+      operate(eff->op, power, eff->value);
+      break;
+    case REQ_TECH:
+      if (player_knows_tech(city_owner(pcity), eff->req.tech)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_GOV:
+      if (get_gov_pcity(pcity) == eff->req.gov) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_BUILDING:
+      if (city_got_building(pcity, eff->req.building)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_WONDER:
+      if (city_affected_by_wonder(pcity, eff->req.wonder)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    default:
+      freelog(LOG_ERROR, "city_building_power_func: %d", eff->type);
+      break;
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline void city_tile_power_func(struct city *pcity,
+                                       struct tile *ptile,
+                                       struct effect *eff, int *power)
+{
+  switch (eff->type) {
+    case REQ_NONE:
+      operate(eff->op, power, eff->value);
+      break;
+    case REQ_TECH:
+      if (player_knows_tech(city_owner(pcity), eff->req.tech)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_GOV:
+      if (get_gov_pcity(pcity) == eff->req.gov) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_BUILDING:
+      if (city_got_building(pcity, eff->req.building)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_WONDER:
+      if (city_affected_by_wonder(pcity, eff->req.wonder)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_SPECIAL:
+      if (tile_has_special(ptile, eff->req.special)) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    case REQ_TERRAIN:
+      if (ptile->terrain == eff->req.terrain) {
+       operate(eff->op, power, eff->value);
+      }
+      break;
+    default:
+      freelog(LOG_ERROR, "city_tile_power_func: %d", eff->type);
+      break;
+  }
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+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 is_building_unique(Impr_Type_id id, enum effect_type eff)
+{
+  return (!*get_building_eff_group(id, eff));
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static inline bool is_unique_wonder(Impr_Type_id id, enum effect_type eff)
+{
+  return (is_wonder(id) && is_building_unique(id, eff));
+}
+
+
+/**************************************************************************
+...
+**************************************************************************/
+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_bonus_local(struct city *pcity, enum effect_type eff)
+{
+  int bonus = 0;
+
+  /* get bonus effect from improvements or equivalent effect buildings. */
+  building_vector_iterate(get_effect_buildings(eff), elt) {
+    if (!is_unique_wonder(*elt, eff)) {
+      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_bonus_global(struct city *pcity, enum effect_type eff)
+{
+  int bonus = 0;
+
+  /* get bonus effect from unique wonders. */
+  building_vector_iterate(get_effect_buildings(eff), elt) {
+    if (is_unique_wonder(*elt, eff)) {
+      if (city_affected_by_wonder(pcity, *elt)) {
+       bonus += get_city_power(pcity, *elt, 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 freeciv/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-16 15:10:57.303589480 +0100
@@ -0,0 +1,62 @@
+#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_bonus(struct player *plr, enum effect_type eff);
+
+int get_city_bonus(struct city *pcity, enum effect_type eff);
+int get_city_bonus_local(struct city *pcity, enum effect_type eff);
+int get_city_bonus_global(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 freeciv/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 freeciv/diff_ignore freecvs/common/packets.def 
freeciv/common/packets.def
--- freecvs/common/packets.def  2004-05-11 18:18:19.000000000 +0100
+++ freeciv/common/packets.def  2004-05-16 15:19:49.018756488 +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
@@ -1274,3 +1279,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 freeciv/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 freeciv/diff_ignore freecvs/server/ruleset.c 
freeciv/server/ruleset.c
--- freecvs/server/ruleset.c    2004-05-11 18:18:20.000000000 +0100
+++ freeciv/server/ruleset.c    2004-05-16 15:08:47.087385352 +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]);
     
@@ -3155,6 +3256,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]
  • [Freeciv-Dev] (PR#8754) effects patch, Vasco Alexandre da Silva Costa <=