Complete.Org: Mailing Lists: Archives: freeciv-dev: January 2005:
[Freeciv-Dev] (PR#12019) Effects TNG
Home

[Freeciv-Dev] (PR#12019) Effects TNG

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: vasc@xxxxxxxxxxxxxx
Subject: [Freeciv-Dev] (PR#12019) Effects TNG
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 31 Jan 2005 10:26:22 -0800
Reply-to: bugs@xxxxxxxxxxx

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

Here's a new patch.  I combined the rulesets with the v4 patch.  There
were no other changes.

Bug-hunters, please test.  Modpack authors, please comment on the
design.  AI people, please review the AI bits (I suggest diff -b). 
We'll probably commit this pretty soon.

-jason

Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.190
diff -u -r1.190 aicity.c
--- ai/aicity.c 22 Jan 2005 19:45:38 -0000      1.190
+++ ai/aicity.c 31 Jan 2005 18:20:53 -0000
@@ -245,6 +245,10 @@
   struct tile *ptile = pcity->tile;
   bool capital = is_capital(pcity);
   struct government *gov = get_gov_pplayer(pplayer);
+  struct req_source source = {
+    .type = REQ_BUILDING,
+    .value.building = id
+  };
 
   /* Base want is calculated above using a more direct approach. */
   v += base_want(pplayer, pcity, id);
@@ -262,277 +266,294 @@
   cities[REQ_RANGE_CITY] = 1;
   cities[REQ_RANGE_LOCAL] = 0;
 
-  /* Calculate desire value. */
-  effect_type_vector_iterate(get_building_effect_types(id), ptype) {
-    effect_list_iterate(get_building_effects(id, *ptype), peff) {
-      if (is_effect_useful(TARGET_BUILDING, pplayer, pcity, id,
-                          NULL, id, peff)) {
-       int amount = peff->value, c = cities[peff->range];
-        struct city *palace = find_palace(pplayer);
-
-       switch (*ptype) {
-         case EFT_PROD_TO_GOLD:
-            /* Since coinage contains some entirely spurious ruleset values,
-             * we need to return here with some spurious want. */
-            pcity->ai.building_want[id] = TRADE_WEIGHTING;
-            return;
-          /* These have already been evaluated in base_want() */
-          case EFT_CAPITAL_CITY:
-         case EFT_UPKEEP_FREE:
-         case EFT_POLLU_POP_PCT:
-         case EFT_POLLU_PROD_PCT:
-         case EFT_TRADE_PER_TILE:
-         case EFT_TRADE_INC_TILE:
-         case EFT_FOOD_INC_TILE:
-         case EFT_TRADE_ADD_TILE:
-         case EFT_PROD_INC_TILE:
-         case EFT_PROD_PER_TILE:
-         case EFT_PROD_ADD_TILE:
-         case EFT_FOOD_PER_TILE:
-         case EFT_FOOD_ADD_TILE:
-         case EFT_PROD_BONUS:
-          case EFT_TAX_BONUS:
-          case EFT_SCIENCE_BONUS:
-         case EFT_LUXURY_BONUS:
-          case EFT_CORRUPT_PCT:
-          case EFT_WASTE_PCT:
-           break;
-
-          /* WAG evaluated effects */
-         case EFT_INCITE_DIST_PCT:
-            if (palace) {
-              v += real_map_distance(pcity->tile, palace->tile);
-            }
-            break;
-         case EFT_MAKE_HAPPY:
-            /* TODO */
-            break;
-         case EFT_UNIT_RECOVER:
-            /* TODO */
-            break;
-         case EFT_NO_UNHAPPY:
-            v += (get_entertainers(pcity)
-                 + pcity->ppl_unhappy[4]) * 20;
-            break;
-         case EFT_FORCE_CONTENT:
-           if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
-             v += (pcity->ppl_unhappy[4]
-                   + get_entertainers(pcity)) * 20;
-             v += 5 * c;
-           }
-           break;
-         case EFT_MAKE_CONTENT_MIL_PER:
-         case EFT_MAKE_CONTENT:
-           if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
-              v += MIN(pcity->ppl_unhappy[4]
-                      + get_entertainers(pcity),
-                       amount) * 20;
-              v += MIN(amount, 5) * c;
-           }
-           break;
-         case EFT_MAKE_CONTENT_MIL:
-           if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
-             v += pcity->ppl_unhappy[4] * amount
-               * MAX(unit_list_size(pcity->units_supported)
-                   - gov->free_happy, 0) * 2;
-             v += c * MAX(amount + 2 - gov->free_happy, 1);
-           }
-           break;
-         case EFT_TECH_PARASITE:
-           v += (total_bulbs_required(pplayer) * (100 - game.freecost)
-               * (nplayers - amount)) / (nplayers * amount * 100);
-           break;
-         case EFT_GROWTH_FOOD:
-           v += c * 4 + (amount / 7) * pcity->surplus[O_FOOD];
-           break;
-         case EFT_AIRLIFT:
-            /* FIXME: We need some smart algorithm here. The below is 
-             * totally braindead. */
-           v += c + MIN(ai->stats.units[UCL_LAND], 13);
-           break;
-         case EFT_ANY_GOVERNMENT:
-           if (!can_change_to_government(pplayer, ai->goal.govt.idx)) {
-             v += MIN(MIN(ai->goal.govt.val, 65),
-                 num_unknown_techs_for_goal(pplayer, ai->goal.govt.req) * 10);
-           }
-           break;
-         case EFT_ENABLE_NUKE:
-           /* Treat nuke as a Cruise Missile upgrade */
-           v += 20 + ai->stats.units[UCL_MISSILE] * 5;
-           break;
-         case EFT_ENABLE_SPACE:
-           if (game.spacerace) {
-             v += 5;
-             if (ai->diplomacy.production_leader == pplayer) {
-               v += 100;
+  effect_list_iterate(get_req_source_effects(&source), peffect) {
+    struct requirement *mypreq;
+    bool useful;
+
+    if (is_effect_disabled(TARGET_BUILDING, pplayer, pcity,
+                          id, NULL, peffect)) {
+      continue;
+    }
+
+    mypreq = NULL;
+    useful = TRUE;
+    requirement_list_iterate(peffect->reqs, preq) {
+      if (preq->source.type == REQ_BUILDING
+         && preq->source.value.building == id) {
+       mypreq = preq;
+      }
+      if (!is_req_active(TARGET_BUILDING, pplayer, pcity, id, NULL, preq)) {
+       useful = FALSE;
+       break;
+      }
+    } requirement_list_iterate_end;
+
+    if (useful) {
+      int amount = peffect->value, c = cities[mypreq->range];
+      struct city *palace = find_palace(pplayer);
+
+      switch (peffect->type) {
+       case EFT_PROD_TO_GOLD:
+         /* Since coinage contains some entirely spurious ruleset values,
+          * we need to return here with some spurious want. */
+         pcity->ai.building_want[id] = TRADE_WEIGHTING;
+         return;
+       /* These have already been evaluated in base_want() */
+       case EFT_CAPITAL_CITY:
+       case EFT_UPKEEP_FREE:
+       case EFT_POLLU_POP_PCT:
+       case EFT_POLLU_PROD_PCT:
+       case EFT_TRADE_PER_TILE:
+       case EFT_TRADE_INC_TILE:
+       case EFT_FOOD_INC_TILE:
+       case EFT_TRADE_ADD_TILE:
+       case EFT_PROD_INC_TILE:
+       case EFT_PROD_PER_TILE:
+       case EFT_PROD_ADD_TILE:
+       case EFT_FOOD_PER_TILE:
+       case EFT_FOOD_ADD_TILE:
+       case EFT_PROD_BONUS:
+       case EFT_TAX_BONUS:
+       case EFT_SCIENCE_BONUS:
+       case EFT_LUXURY_BONUS:
+       case EFT_CORRUPT_PCT:
+       case EFT_WASTE_PCT:
+         break;
+
+       /* WAG evaluated effects */
+       case EFT_INCITE_DIST_PCT:
+         if (palace) {
+           v += real_map_distance(pcity->tile, palace->tile);
+         }
+         break;
+       case EFT_MAKE_HAPPY:
+         /* TODO */
+         break;
+       case EFT_UNIT_RECOVER:
+         /* TODO */
+         break;
+       case EFT_NO_UNHAPPY:
+         v += (get_entertainers(pcity)
+               + pcity->ppl_unhappy[4]) * 20;
+         break;
+       case EFT_FORCE_CONTENT:
+         if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
+           v += (pcity->ppl_unhappy[4]
+                 + get_entertainers(pcity)) * 20;
+           v += 5 * c;
+         }
+         break;
+       case EFT_MAKE_CONTENT_MIL_PER:
+       case EFT_MAKE_CONTENT:
+         if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
+           v += MIN(pcity->ppl_unhappy[4]
+                    + get_entertainers(pcity),
+                    amount) * 20;
+           v += MIN(amount, 5) * c;
+         }
+         break;
+       case EFT_MAKE_CONTENT_MIL:
+         if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
+           v += pcity->ppl_unhappy[4] * amount
+             * MAX(unit_list_size(pcity->units_supported)
+                 - gov->free_happy, 0) * 2;
+           v += c * MAX(amount + 2 - gov->free_happy, 1);
+         }
+         break;
+       case EFT_TECH_PARASITE:
+         v += (total_bulbs_required(pplayer) * (100 - game.freecost)
+             * (nplayers - amount)) / (nplayers * amount * 100);
+         break;
+       case EFT_GROWTH_FOOD:
+         v += c * 4 + (amount / 7) * pcity->surplus[O_FOOD];
+         break;
+       case EFT_AIRLIFT:
+         /* FIXME: We need some smart algorithm here. The below is 
+          * totally braindead. */
+         v += c + MIN(ai->stats.units[UCL_LAND], 13);
+         break;
+       case EFT_ANY_GOVERNMENT:
+         if (!can_change_to_government(pplayer, ai->goal.govt.idx)) {
+           v += MIN(MIN(ai->goal.govt.val, 65),
+               num_unknown_techs_for_goal(pplayer, ai->goal.govt.req) * 10);
+         }
+         break;
+       case EFT_ENABLE_NUKE:
+         /* Treat nuke as a Cruise Missile upgrade */
+         v += 20 + ai->stats.units[UCL_MISSILE] * 5;
+         break;
+       case EFT_ENABLE_SPACE:
+         if (game.spacerace) {
+           v += 5;
+           if (ai->diplomacy.production_leader == pplayer) {
+             v += 100;
+           }
+         }
+         break;
+       case EFT_GIVE_IMM_TECH:
+         v += ((total_bulbs_required(pplayer) * amount 
+               + game.researchcost)
+             * TRADE_WEIGHTING - pplayer->research.bulbs_researched 
+             * TRADE_WEIGHTING) / MORT;
+         break;
+       case EFT_HAVE_EMBASSIES:
+         v += 5 * nplayers;
+         break;
+       case EFT_REVEAL_CITIES:
+       case EFT_NO_ANARCHY:
+         break;  /* Useless for AI */
+       case EFT_NO_SINK_DEEP:
+         v += 15 + ai->stats.triremes * 5;
+         break;
+       case EFT_NUKE_PROOF:
+         if (ai->threats.nuclear) {
+           v += pcity->size * unit_list_size(ptile->units) * (capital + 1);
+         }
+         break;
+       case EFT_REVEAL_MAP:
+         if (!ai->explore.land_done || !ai->explore.sea_done) {
+           v += 10;
+         }
+         break;
+       case EFT_SIZE_UNLIMIT:
+         amount = 20; /* really big city */
+         /* there not being a break here is deliberate, mind you */
+       case EFT_SIZE_ADJ: 
+         if (!city_can_grow_to(pcity, pcity->size + 1)) {
+           v += pcity->surplus[O_FOOD] * ai->food_priority * amount;
+           if (pcity->size == game.aqueduct_size) {
+             v += 30 * pcity->surplus[O_FOOD];
+           }
+         }
+         v += c * amount * 4 / game.aqueduct_size;
+         break;
+       case EFT_SS_STRUCTURAL:
+       case EFT_SS_COMPONENT:
+       case EFT_SS_MODULE:
+         if (game.spacerace
+             /* If someone has started building spaceship already or
+              * we have chance to win a spacerace */
+             && (ai->diplomacy.spacerace_leader
+                 || ai->diplomacy.production_leader == pplayer)) {
+           v += 95;
+         }
+         break;
+       case EFT_SPY_RESISTANT:
+         /* Uhm, problem: City Wall has -50% here!! */
+         break;
+       case EFT_SEA_MOVE:
+         v += ai->stats.units[UCL_SEA] * 8 * amount;
+         break;
+       case EFT_UNIT_NO_LOSE_POP:
+         v += unit_list_size(ptile->units) * 2;
+         break;
+       case EFT_LAND_REGEN:
+         v += 15 * c + ai->stats.units[UCL_LAND] * 3;
+         break;
+       case EFT_SEA_REGEN:
+         v += 15 * c + ai->stats.units[UCL_SEA] * 3;
+         break;
+       case EFT_AIR_REGEN:
+         v += 15 * c + ai->stats.units[UCL_AIR] * 3;
+         break;
+       case EFT_LAND_VET_COMBAT:
+         v += 2 * c + ai->stats.units[UCL_LAND] * 2;
+         break;
+       case EFT_LAND_VETERAN:
+         v += 5 * c + ai->stats.units[UCL_LAND];
+         break;
+       case EFT_SEA_VETERAN:
+         v += 5 * c + ai->stats.units[UCL_SEA];
+         break;
+       case EFT_AIR_VETERAN:
+         v += 5 * c + ai->stats.units[UCL_AIR];
+         break;
+       case EFT_UPGRADE_UNIT:
+         v += ai->stats.units[UCL_LAST];
+         if (amount == 1) {
+           v *= 2;
+         } else if (amount == 2) {
+           v *= 3;
+         } else {
+           v *= 4;
+         }
+         break;
+       case EFT_SEA_DEFEND:
+         if (ai_handicap(pplayer, H_DEFENSIVE)) {
+           v += amount / 10; /* make AI slow */
+         }
+         if (is_ocean(map_get_terrain(pcity->tile))) {
+           v += ai->threats.ocean[-map_get_continent(pcity->tile)]
+                ? amount/5 : amount/20;
+         } else {
+           adjc_iterate(pcity->tile, tile2) {
+             if (is_ocean(map_get_terrain(tile2))) {
+               if (ai->threats.ocean[-map_get_continent(tile2)]) {
+                 v += amount/5;
+                 break;
+               }
+             }
+           } adjc_iterate_end;
+         }
+         v += (amount/20 + ai->threats.invasions - 1) * c; /* for wonder */
+         if (capital && ai->threats.invasions) {
+           v += amount; /* defend capital! */
+         }
+         break;
+       case EFT_AIR_DEFEND:
+         if (ai_handicap(pplayer, H_DEFENSIVE)) {
+           v += amount / 15; /* make AI slow */
+         }
+         v += (ai->threats.air && ai->threats.continent[ptile->continent]) 
+           ? amount/10 * 5 + amount/10 * c : c;
+         break;
+       case EFT_MISSILE_DEFEND:
+         if (ai->threats.missile
+             && (ai->threats.continent[ptile->continent] || capital)) {
+           v += amount/10 * 5 + (amount/10 - 1) * c;
+         }
+         break;
+       case EFT_LAND_DEFEND:
+         if (ai_handicap(pplayer, H_DEFENSIVE)) {
+           v += amount / 10; /* make AI slow */
+         }
+         if (ai->threats.continent[ptile->continent]
+             || capital
+             || (ai->threats.invasions
+               && is_water_adjacent_to_tile(pcity->tile))) {
+           v += amount / (!ai->threats.igwall ? (15 - capital * 5) : 15);
+         }
+         v += (1 + ai->threats.invasions + !ai->threats.igwall) * c;
+         break;
+       case EFT_NO_INCITE:
+         if (!government_has_flag(gov, G_UNBRIBABLE)) {
+           v += MAX((game.diplchance * 2 - game.incite_cost.total_factor) / 2
+               - game.incite_cost.improvement_factor * 5
+               - game.incite_cost.unit_factor * 5, 0);
+         }
+         break;
+       case EFT_REGEN_REPUTATION:
+         v += (GAME_MAX_REPUTATION - pplayer->reputation) * 50 / 
+                 GAME_MAX_REPUTATION + 
+               amount * 4;
+         break;
+       case EFT_GAIN_AI_LOVE:
+         players_iterate(aplayer) {
+           if (aplayer->ai.control) {
+             if (ai_handicap(pplayer, H_DEFENSIVE)) {
+               v += amount / 10;
+             } else {
+               v += amount / 20;
              }
            }
-           break;
-         case EFT_GIVE_IMM_TECH:
-           v += ((total_bulbs_required(pplayer) * amount 
-                 + game.researchcost)
-               * TRADE_WEIGHTING - pplayer->research.bulbs_researched 
-               * TRADE_WEIGHTING) / MORT;
-           break;
-         case EFT_HAVE_EMBASSIES:
-           v += 5 * nplayers;
-           break;
-         case EFT_REVEAL_CITIES:
-         case EFT_NO_ANARCHY:
-           break;  /* Useless for AI */
-         case EFT_NO_SINK_DEEP:
-           v += 15 + ai->stats.triremes * 5;
-           break;
-         case EFT_NUKE_PROOF:
-           if (ai->threats.nuclear) {
-             v += pcity->size * unit_list_size(ptile->units) * (capital + 1);
-           }
-           break;
-         case EFT_REVEAL_MAP:
-           if (!ai->explore.land_done || !ai->explore.sea_done) {
-             v += 10;
-           }
-           break;
-         case EFT_SIZE_UNLIMIT:
-           amount = 20; /* really big city */
-           /* there not being a break here is deliberate, mind you */
-         case EFT_SIZE_ADJ: 
-            if (!city_can_grow_to(pcity, pcity->size + 1)) {
-             v += pcity->surplus[O_FOOD] * ai->food_priority * amount;
-              if (pcity->size == game.aqueduct_size) {
-                v += 30 * pcity->surplus[O_FOOD];
-              }
-           }
-           v += c * amount * 4 / game.aqueduct_size;
-           break;
-         case EFT_SS_STRUCTURAL:
-         case EFT_SS_COMPONENT:
-         case EFT_SS_MODULE:
-           if (game.spacerace
-               /* If someone has started building spaceship already or
-                * we have chance to win a spacerace */
-               && (ai->diplomacy.spacerace_leader
-                   || ai->diplomacy.production_leader == pplayer)) {
-             v += 95;
-           }
-           break;
-         case EFT_SPY_RESISTANT:
-           /* Uhm, problem: City Wall has -50% here!! */
-           break;
-         case EFT_SEA_MOVE:
-           v += ai->stats.units[UCL_SEA] * 8 * amount;
-           break;
-         case EFT_UNIT_NO_LOSE_POP:
-           v += unit_list_size(ptile->units) * 2;
-           break;
-         case EFT_LAND_REGEN:
-           v += 15 * c + ai->stats.units[UCL_LAND] * 3;
-           break;
-         case EFT_SEA_REGEN:
-           v += 15 * c + ai->stats.units[UCL_SEA] * 3;
-           break;
-         case EFT_AIR_REGEN:
-           v += 15 * c + ai->stats.units[UCL_AIR] * 3;
-           break;
-         case EFT_LAND_VET_COMBAT:
-           v += 2 * c + ai->stats.units[UCL_LAND] * 2;
-           break;
-         case EFT_LAND_VETERAN:
-           v += 5 * c + ai->stats.units[UCL_LAND];
-           break;
-         case EFT_SEA_VETERAN:
-           v += 5 * c + ai->stats.units[UCL_SEA];
-           break;
-         case EFT_AIR_VETERAN:
-           v += 5 * c + ai->stats.units[UCL_AIR];
-           break;
-         case EFT_UPGRADE_UNIT:
-           v += ai->stats.units[UCL_LAST];
-           if (amount == 1) {
-             v *= 2;
-           } else if (amount == 2) {
-             v *= 3;
-           } else {
-             v *= 4;
-           }
-           break;
-         case EFT_SEA_DEFEND:
-           if (ai_handicap(pplayer, H_DEFENSIVE)) {
-             v += amount / 10; /* make AI slow */
-           }
-            if (is_ocean(map_get_terrain(pcity->tile))) {
-              v += ai->threats.ocean[-map_get_continent(pcity->tile)]
-                   ? amount/5 : amount/20;
-            } else {
-              adjc_iterate(pcity->tile, tile2) {
-                if (is_ocean(map_get_terrain(tile2))) {
-                  if (ai->threats.ocean[-map_get_continent(tile2)]) {
-                    v += amount/5;
-                   break;
-                  }
-                }
-              } adjc_iterate_end;
-            }
-           v += (amount/20 + ai->threats.invasions - 1) * c; /* for wonder */
-           if (capital && ai->threats.invasions) {
-             v += amount; /* defend capital! */
-           }
-           break;
-         case EFT_AIR_DEFEND:
-           if (ai_handicap(pplayer, H_DEFENSIVE)) {
-             v += amount / 15; /* make AI slow */
-           }
-           v += (ai->threats.air && ai->threats.continent[ptile->continent]) 
-             ? amount/10 * 5 + amount/10 * c : c;
-           break;
-         case EFT_MISSILE_DEFEND:
-           if (ai->threats.missile
-               && (ai->threats.continent[ptile->continent] || capital)) {
-             v += amount/10 * 5 + (amount/10 - 1) * c;
-           }
-           break;
-         case EFT_LAND_DEFEND:
-           if (ai_handicap(pplayer, H_DEFENSIVE)) {
-             v += amount / 10; /* make AI slow */
-           }
-           if (ai->threats.continent[ptile->continent]
-               || capital
-               || (ai->threats.invasions
-                 && is_water_adjacent_to_tile(pcity->tile))) {
-              v += amount / (!ai->threats.igwall ? (15 - capital * 5) : 15);
-           }
-           v += (1 + ai->threats.invasions + !ai->threats.igwall) * c;
-           break;
-         case EFT_NO_INCITE:
-           if (!government_has_flag(gov, G_UNBRIBABLE)) {
-             v += MAX((game.diplchance * 2 - game.incite_cost.total_factor) / 2
-                 - game.incite_cost.improvement_factor * 5
-                 - game.incite_cost.unit_factor * 5, 0);
-           }
-           break;
-          case EFT_REGEN_REPUTATION:
-            v += (GAME_MAX_REPUTATION - pplayer->reputation) * 50 / 
-                   GAME_MAX_REPUTATION + 
-                 amount * 4;
-            break;
-         case EFT_GAIN_AI_LOVE:
-            players_iterate(aplayer) {
-              if (aplayer->ai.control) {
-                if (ai_handicap(pplayer, H_DEFENSIVE)) {
-                  v += amount / 10;
-                } else {
-                  v += amount / 20;
-                }
-              }
-            } players_iterate_end;
-            break;
-         case EFT_LAST:
-           freelog(LOG_ERROR, "Bad effect type.");
-           break;
-       }
+         } players_iterate_end;
+         break;
+       case EFT_LAST:
+         freelog(LOG_ERROR, "Bad effect type.");
+         break;
       }
-    } effect_list_iterate_end;
-  } effect_type_vector_iterate_end;
+    }
+  } effect_list_iterate_end;
 
   /* Reduce want if building gets obsoleted soon */
   if (tech_exists(pimpr->obsolete_by)) {
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.49
diff -u -r1.49 aidata.c
--- ai/aidata.c 22 Jan 2005 19:45:38 -0000      1.49
+++ ai/aidata.c 31 Jan 2005 18:20:53 -0000
@@ -59,11 +59,16 @@
   memset(count, 0, sizeof(count));
 
   impr_type_iterate(id) {
+    struct req_source source = {
+      .type = REQ_BUILDING,
+      .value.building = id
+    };
+
     ai->impr_calc[id] = AI_IMPR_ESTIMATE;
 
     /* Find largest extension */
-    effect_type_vector_iterate(get_building_effect_types(id), ptype) {
-      switch (*ptype) {
+    effect_list_iterate(get_req_source_effects(&source), peffect) {
+      switch (peffect->type) {
 #if 0
       /* TODO */
       case EFT_FORCE_CONTENT:
@@ -92,19 +97,21 @@
       case EFT_TRADE_INC_TILE:
       case EFT_TRADE_PER_TILE:
       case EFT_UPKEEP_FREE:
-      effect_list_iterate(get_building_effects(id, *ptype), peff) {
-        ai->impr_calc[id] = AI_IMPR_CALCULATE;
-        if (peff->range > ai->impr_range[id]) {
-          ai->impr_range[id] = peff->range;
-        }
-      } effect_list_iterate_end;
+       requirement_list_iterate(peffect->reqs, preq) {
+         if (preq->source.type == REQ_BUILDING
+             && preq->source.value.building == id) {
+           ai->impr_calc[id] = AI_IMPR_CALCULATE;
+           if (preq->range > ai->impr_range[id]) {
+             ai->impr_range[id] = preq->range;
+           }
+         }
+       } requirement_list_iterate_end;
       break;
       default:
       /* Nothing! */
       break;
       }
-    } effect_type_vector_iterate_end;
-    
+    } effect_list_iterate_end;
   } impr_type_iterate_end;
 }
 
Index: client/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.57
diff -u -r1.57 citydlg_common.c
--- client/citydlg_common.c     22 Jan 2005 19:45:38 -0000      1.57
+++ client/citydlg_common.c     31 Jan 2005 18:20:54 -0000
@@ -439,22 +439,26 @@
 
   if (eft != EFT_LAST) {
     int base = total, bonus = 100;
-    struct effect_source_vector sources;
+    struct effect_list *plist = effect_list_new();
 
-    (void) get_city_bonus_sources(&sources, pcity, eft);
+    (void) get_city_bonus_effects(plist, pcity, eft);
 
-    effect_source_vector_iterate(&sources, s) {
+    effect_list_iterate(plist, peffect) {
+      char buf2[512];
       int new_total;
 
-      bonus += s->effect_value;
+      get_effect_req_text(peffect, buf2, sizeof(buf2));
+
+      bonus += peffect->value;
       new_total = bonus * base / 100;
       cat_snprintf(buf, bufsz,
                   _("%+4d : Bonus from %s (%+d%%)\n"),
-                  (new_total - total), get_improvement_name(s->building),
-                  s->effect_value);
+                  (new_total - total), buf2,
+                  peffect->value);
       total = new_total;
-    } effect_source_vector_iterate_end;
-    effect_source_vector_free(&sources);
+    } effect_list_iterate_end;
+    effect_list_unlink_all(plist);
+    effect_list_free(plist);
   }
 
   if (pcity->waste[otype] != 0) {
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.461
diff -u -r1.461 packhand.c
--- client/packhand.c   29 Jan 2005 17:58:17 -0000      1.461
+++ client/packhand.c   31 Jan 2005 18:20:54 -0000
@@ -2833,31 +2833,18 @@
 }
 
 /**************************************************************************
-  Add group data to ruleset cache.  
+  Add effect data to ruleset cache.  
 **************************************************************************/
-void handle_ruleset_cache_group(struct packet_ruleset_cache_group *packet)
+void handle_ruleset_effect(struct packet_ruleset_effect *packet)
 {
-  struct effect_group *pgroup;
-  int i;
-
-  pgroup = effect_group_new(packet->name);
-
-  for (i = 0; i < packet->num_elements; i++) {
-    effect_group_add_element(pgroup, packet->source_buildings[i],
-                            packet->ranges[i], packet->survives[i]);
-  }
+  recv_ruleset_effect(packet);
 }
 
 /**************************************************************************
-  Add effect data to ruleset cache.  
+  Add effect requirement data to ruleset cache.  
 **************************************************************************/
-void handle_ruleset_cache_effect(struct packet_ruleset_cache_effect *packet)
+void handle_ruleset_effect_req(struct packet_ruleset_effect_req *packet)
 {
-  struct requirement req = req_from_values(packet->req_type, REQ_RANGE_CITY,
-                                          FALSE, packet->req_value);
-
-  ruleset_cache_add(packet->id, packet->effect_type, packet->range,
-                   packet->survives, packet->eff_value,
-                   &req, packet->group_id);
+  recv_ruleset_effect_req(packet);
 }
 
Index: client/text.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/text.c,v
retrieving revision 1.21
diff -u -r1.21 text.c
--- client/text.c       22 Jan 2005 19:45:39 -0000      1.21
+++ client/text.c       31 Jan 2005 18:20:54 -0000
@@ -724,17 +724,21 @@
 const char *get_happiness_buildings(const struct city *pcity)
 {
   int faces = 0;
-  struct effect_source_vector sources;
+  struct effect_list *plist = effect_list_new();
+  char buf[512];
   INIT;
 
   add_line(_("Buildings: "));
 
-  get_city_bonus_sources(&sources, pcity, EFT_MAKE_CONTENT);
-  effect_source_vector_iterate(&sources, src) {
+  get_city_bonus_effects(plist, pcity, EFT_MAKE_CONTENT);
+
+  effect_list_iterate(plist, peffect) {
     faces++;
-    add(_("%s. "), get_improvement_name(src->building));
-  } effect_source_vector_iterate_end;
-  effect_source_vector_free(&sources);
+    get_effect_req_text(peffect, buf, sizeof(buf));
+    add(_("%s. "), buf);
+  } effect_list_iterate_end;
+  effect_list_unlink_all(plist);
+  effect_list_free(plist);
 
   if (faces == 0) {
     add(_("None. "));
@@ -749,31 +753,23 @@
 const char *get_happiness_wonders(const struct city *pcity)
 {
   int faces = 0;
-  struct effect_source_vector sources;
+  struct effect_list *plist = effect_list_new();
+  char buf[512];
   INIT;
 
   add_line(_("Wonders: "));
+  get_city_bonus_effects(plist, pcity, EFT_MAKE_HAPPY);
+  get_city_bonus_effects(plist, pcity, EFT_FORCE_CONTENT);
+  get_city_bonus_effects(plist, pcity, EFT_NO_UNHAPPY);
 
-  get_city_bonus_sources(&sources, pcity, EFT_MAKE_HAPPY);
-  effect_source_vector_iterate(&sources, src) {
-    faces++;
-    add(_("%s. "), get_improvement_name(src->building));
-  } effect_source_vector_iterate_end;
-  effect_source_vector_free(&sources);
-
-  get_city_bonus_sources(&sources, pcity, EFT_FORCE_CONTENT);
-  effect_source_vector_iterate(&sources, src) {
+  effect_list_iterate(plist, peffect) {
     faces++;
-    add(_("%s. "), get_improvement_name(src->building));
-  } effect_source_vector_iterate_end;
-  effect_source_vector_free(&sources);
+    get_effect_req_text(peffect, buf, sizeof(buf));
+    add(_("%s. "), buf);
+  } effect_list_iterate_end;
 
-  get_city_bonus_sources(&sources, pcity, EFT_NO_UNHAPPY);
-  effect_source_vector_iterate(&sources, src) {
-    faces++;
-    add(_("%s. "), get_improvement_name(src->building));
-  } effect_source_vector_iterate_end;
-  effect_source_vector_free(&sources);
+  effect_list_unlink_all(plist);
+  effect_list_free(plist);
 
   if (faces == 0) {
     add(_("None. "));
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.308
diff -u -r1.308 city.c
--- common/city.c       29 Jan 2005 08:51:18 -0000      1.308
+++ common/city.c       31 Jan 2005 18:20:55 -0000
@@ -671,7 +671,7 @@
   for (i = 0; i < MAX_NUM_REQS; i++) {
     struct requirement *req = &game.rgame.specialists[type].req[i];
 
-    if (req->type == REQ_NONE) {
+    if (req->source.type == REQ_NONE) {
       break; /* Short-circuit any more checks. */
     } else if (!is_req_active(TARGET_CITY, city_owner(pcity), pcity,
                              B_LAST, NULL, req)) {
Index: common/effects.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.c,v
retrieving revision 1.21
diff -u -r1.21 effects.c
--- common/effects.c    22 Jan 2005 19:45:41 -0000      1.21
+++ common/effects.c    31 Jan 2005 18:20:55 -0000
@@ -212,152 +212,114 @@
   number of possible sources increases.
 **************************************************************************/
 
-/*
- * A group lists which sources are in it and at what range.
- * Each effect also lists which group it is in.  So an effect is in the
- * group if its source is listed in the group, and the effect lists the
- * group as its own.
- *
- * Only the first applicable effect in a group will be active.  Any others
- * are simply ignored.
- *
- * Actually this isn't quite true.  The check is done on buildings, not
- * on effects.  A building in a group may obsolete the effect of a building
- * later in the group, even if the first building doesn't have any effects
- * that are actually in the group.  However only the effects of the second
- * building that are actually in the group will be obsoleted.
- */
-struct effect_group_element {
-  Impr_Type_id source_building;
-  enum req_range range;
-  bool survives;
-};
-
-#define SPECLIST_TAG effect_group_element
-#define SPECLIST_TYPE struct effect_group_element
-#include "speclist.h"
-
-#define effect_group_element_list_iterate(list, elt) \
-  TYPED_LIST_ITERATE(struct effect_group_element, list, elt)
-#define effect_group_element_list_iterate_end  LIST_ITERATE_END
-
-struct effect_group {
-  char *name;
-  int id;
-  struct effect_group_element_list *elements;
-};
-
-#define SPECLIST_TAG effect_group
-#define SPECLIST_TYPE struct effect_group
-#include "speclist.h"
-
-#define effect_group_list_iterate(list, pgroup) \
-  TYPED_LIST_ITERATE(struct effect_group, list, pgroup)
-#define effect_group_list_iterate_end  LIST_ITERATE_END
-
 /**************************************************************************
   Ruleset cache. The cache is created during ruleset loading and the data
   is organized to enable fast queries.
 **************************************************************************/
 static struct {
-  struct {
-    /* This cache shows for each effect, which buildings provide it. */
-    struct building_vector buildings;
+  /* A single list containing every effect. */
+  struct effect_list *tracker;
 
-    /* This array provides a full list of the effects of this type provided
-     * by each building.  (It's not really a cache, it's the real data.) */
-    struct effect_list *buckets[B_LAST];
-  } effects[EFT_LAST];
+  /* This array provides a full list of the effects of this type
+   * (It's not really a cache, it's the real data.) */
+  struct effect_list *effects[EFT_LAST];
 
-  /* This cache shows for each building, which effect types it provides. */
   struct {
-    struct effect_type_vector types;
-  } buildings[B_LAST];
+    /* This cache shows for each building, which effects it provides. */
+    struct effect_list *buildings[B_LAST];
+  } reqs;
 } ruleset_cache;
 
-static struct effect_group_list *groups;
-static int next_group_id;
-
 
 /**************************************************************************
-  Get a vector of buildings which grant the effect type.
+  Get a list of effects of this type.
 **************************************************************************/
-static struct building_vector *get_buildings_with_effect(enum effect_type e)
+static struct effect_list *get_effects(enum effect_type effect_type)
 {
-  return &ruleset_cache.effects[e].buildings;
+  return ruleset_cache.effects[effect_type];
 }
 
 /**************************************************************************
-  Get a list of effects of this type granted by a building.
-**************************************************************************/
-struct effect_list *get_building_effects(Impr_Type_id building,
-                                        enum effect_type effect_type)
-{
-  return ruleset_cache.effects[effect_type].buckets[building];
-}
+  Get a list of effects with this requirement source.
 
-/**************************************************************************
-  Get a vector of effect types granted by a building.
+  Note: currently only buildings are supported.
 **************************************************************************/
-struct effect_type_vector *get_building_effect_types(Impr_Type_id id)
+struct effect_list *get_req_source_effects(struct req_source *psource)
 {
-  return &ruleset_cache.buildings[id].types;
+  switch (psource->type) {
+  case REQ_BUILDING:
+    return ruleset_cache.reqs.buildings[psource->value.building];
+  default:
+    return NULL;
+  }
 }
 
 /**************************************************************************
-  Create a new effects group.
+  Add effect to ruleset cache.
 **************************************************************************/
-struct effect_group *effect_group_new(const char *name)
+struct effect *effect_new(enum effect_type type, int value)
 {
-  struct effect_group *group;
+  struct effect *peffect;
 
-  /* Create the group. */
-  group = fc_malloc(sizeof(*group));
-  group->name = mystrdup(name);
-  group->id = next_group_id++;
-  group->elements = effect_group_element_list_new();
+  /* Create the effect. */
+  peffect = fc_malloc(sizeof(*peffect));
+  peffect->type = type;
+  peffect->value = value;
 
-  /* Add this group to the global list of groups. */
-  effect_group_list_append(groups, group);
+  peffect->reqs = requirement_list_new();
+  peffect->nreqs = requirement_list_new();
 
-  return group;
+  /* Now add the effect to the ruleset cache. */
+  effect_list_append(ruleset_cache.tracker, peffect);
+  effect_list_append(get_effects(type), peffect);
+  return peffect;
 }
 
 /**************************************************************************
-  Add a source to an existing effects group.
+  Free effect.
 **************************************************************************/
-void effect_group_add_element(struct effect_group *group,
-                             Impr_Type_id source_building,
-                             enum req_range range, bool survives)
+static void effect_free(struct effect *peffect)
 {
-  struct effect_group_element *elt;
+  requirement_list_iterate(peffect->reqs, preq) {
+    free(preq);
+  } requirement_list_iterate_end;
+  requirement_list_unlink_all(peffect->reqs);
+  requirement_list_free(peffect->reqs);
 
-  /* Create the element. */
-  elt = fc_malloc(sizeof(*elt));
-  elt->source_building = source_building;
-  elt->range = range;
-  elt->survives = survives;
+  requirement_list_iterate(peffect->nreqs, preq) {
+    free(preq);
+  } requirement_list_iterate_end;
+  requirement_list_unlink_all(peffect->nreqs);
+  requirement_list_free(peffect->nreqs);
 
-  /* Append it to the group. */
-  effect_group_element_list_append(group->elements, elt);
+  free(peffect);
 }
 
 /**************************************************************************
-  Find the id of an effects group by name.  Returns -1 if the group is not
-  found.
+  Append requirement to effect.
 **************************************************************************/
-int find_effect_group_id(const char *name)
+void effect_req_append(struct effect *peffect, bool neg,
+                      struct requirement *preq)
 {
-  int group_id = 0;
+  struct requirement_list *req_list;
 
-  effect_group_list_iterate(groups, pgroup) {
-    if (0 == mystrcasecmp(pgroup->name, name)) {
-      return group_id;
-    }
-    group_id++;
-  } effect_group_list_iterate_end;
+  if (neg) {
+    req_list = peffect->nreqs;
+  } else {
+    req_list = peffect->reqs;
+  }
+
+  /* Append requirement to the effect. */
+  requirement_list_append(req_list, preq);
 
-  return -1;
+  /* Add effect to the source's effect list. */
+  if (!neg) {
+    struct effect_list *eff_list = get_req_source_effects(&preq->source);
+
+    if (eff_list) {
+      effect_list_append(eff_list, peffect);
+    }
+  }
 }
 
 /**************************************************************************
@@ -367,21 +329,15 @@
 **************************************************************************/
 void ruleset_cache_init(void)
 {
-  int i, j;
-
-  groups = effect_group_list_new();
-  next_group_id = 0;
+  int i;
 
-  for (i = 0; i < ARRAY_SIZE(ruleset_cache.buildings); i++) {
-    effect_type_vector_init(get_building_effect_types(i));
-  }
+  ruleset_cache.tracker = effect_list_new();
 
   for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
-    building_vector_init(get_buildings_with_effect(i));
-
-    for (j = 0; j < ARRAY_SIZE(ruleset_cache.effects[i].buckets); j++) {
-      ruleset_cache.effects[i].buckets[j] = effect_list_new();
-    }
+    ruleset_cache.effects[i] = effect_list_new();
+  }
+  for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
+    ruleset_cache.reqs.buildings[i] = effect_list_new();
   }
 }
 
@@ -391,166 +347,71 @@
 **************************************************************************/
 void ruleset_cache_free(void)
 {
-  int i, j;
+  int i;
+  struct effect_list *plist = ruleset_cache.tracker;
 
-  for (i = 0; i < ARRAY_SIZE(ruleset_cache.buildings); i++) {
-    effect_type_vector_free(get_building_effect_types(i));
+  if (plist) {
+    effect_list_iterate(plist, peffect) {
+      effect_free(peffect);
+    } effect_list_iterate_end;
+    effect_list_unlink_all(plist);
+    effect_list_free(plist);
+    ruleset_cache.tracker = NULL;
   }
 
   for (i = 0; i < ARRAY_SIZE(ruleset_cache.effects); i++) {
-    building_vector_free(get_buildings_with_effect(i));
-
-    for (j = 0; j < ARRAY_SIZE(ruleset_cache.effects[i].buckets); j++) {
-      struct effect_list *plist = get_building_effects(j, i);
-
-      if (plist != NULL) {
-        effect_list_iterate(plist, peffect) {
-          /* Allocated in ruleset_cache_add. */
-          free(peffect);
-        } effect_list_iterate_end;
-        effect_list_unlink_all(plist);
-        effect_list_free(plist);
-      }
-    }
-  }
-  if (groups != NULL) {
-    effect_group_list_unlink_all(groups);
-    effect_group_list_free(groups);
-  }
-}
-
-/**************************************************************************
-  Add effect to ruleset cache.
-**************************************************************************/
-void ruleset_cache_add(Impr_Type_id source, enum effect_type effect_type,
-                      enum req_range range, bool survives, int eff_value,
-                      struct requirement *req,
-                      int group_id)
-{
-  struct effect *peffect;
-
-  /* Create the effect. */
-  peffect = fc_malloc(sizeof(*peffect));
-  peffect->range = range;
-  peffect->survives = survives;
-  peffect->value = eff_value;
-
-  /* Set effect's requirement data. */
-  peffect->req = *req;
-
-  /* Find the effect's group. */
-  if (group_id >= 0) {
-    peffect->group = effect_group_list_get(groups, group_id);
-  } else {
-    peffect->group = NULL;
-  }
-
-  /* Now add the effect to the ruleset cache. */
-  effect_list_append(get_building_effects(source, effect_type),
-                         peffect);
+    struct effect_list *plist = get_effects(i);
 
-  /* Add building type to the effect type's buildings vector. */
-  {
-    struct building_vector *vec;
-    Impr_Type_id *pbldg;
-
-    vec = get_buildings_with_effect(effect_type);
-
-    /* Append this building to the list of buildings providing the effect.
-     * There is a sanity check to prevent it from being added more than
-     * once.  (It is possible the same building would have multiple effects
-     * of the same type, in which case we don't want to add the building
-     * to the list twice.  However this does assume that all effects from
-     * one building are processed before moving on to the next building. */
-    if (!(pbldg = building_vector_get(vec, -1)) || *pbldg != source) {
-      building_vector_append(vec, &source);
+    if (plist) {
+      effect_list_unlink_all(plist);
+      effect_list_free(plist);
+      ruleset_cache.effects[i] = NULL;
     }
   }
 
-  /* Add effect type to the building's effect types vector. */
-  {
-    struct effect_type_vector *vec;
-    bool exists = FALSE;
-
-    vec = get_building_effect_types(source);
-
-    /* See if it's already in the list. */
-    effect_type_vector_iterate(vec, ptype) {
-      if (*ptype == effect_type) {
-       exists = TRUE;
-       break;
-      }
-    } effect_type_vector_iterate_end;
-
-    /* And if not, append it. */
-    if (!exists) {
-      effect_type_vector_append(vec, &effect_type);
+  for (i = 0; i < ARRAY_SIZE(ruleset_cache.reqs.buildings); i++) {
+    struct req_source source = {
+      .type = REQ_BUILDING,
+      .value.building = i
+    };
+    struct effect_list *plist = get_req_source_effects(&source);
+
+    if (plist) {
+      effect_list_unlink_all(plist);
+      effect_list_free(plist);
+      ruleset_cache.reqs.buildings[i] = NULL;
     }
   }
 }
 
 /**************************************************************************
-  Send the ruleset cache groups data.
+  Receives a new effect.  This is called by the client when the packet
+  arrives.
 **************************************************************************/
-static void send_ruleset_cache_groups(struct conn_list *dest)
+void recv_ruleset_effect(struct packet_ruleset_effect *packet)
 {
-  struct packet_ruleset_cache_group packet;
-  int i;
-
-  effect_group_list_iterate(groups, pgroup) {
-    sz_strlcpy(packet.name, pgroup->name);
-
-    packet.num_elements = effect_group_element_list_size(pgroup->elements);
-    for (i = 0; i < packet.num_elements; i++) {
-      struct effect_group_element *elt;
-
-      elt = effect_group_element_list_get(pgroup->elements, i);
-      packet.source_buildings[i] = elt->source_building;
-      packet.ranges[i] = elt->range;
-      packet.survives[i] = elt->survives;
-    }
-
-    lsend_packet_ruleset_cache_group(dest, &packet);
-  } effect_group_list_iterate_end;
+  effect_new(packet->effect_type, packet->effect_value);
 }
 
 /**************************************************************************
-  Send the ruleset cache effects data.
+  Receives a new effect *requirement*.  This is called by the client when
+  the packet arrives.
 **************************************************************************/
-static void send_ruleset_cache_effects(struct conn_list *dest)
+void recv_ruleset_effect_req(struct packet_ruleset_effect_req *packet)
 {
-  struct packet_ruleset_cache_effect packet;
-  enum effect_type effect_type;
-
-  for (effect_type = 0; effect_type < EFT_LAST; effect_type++) {
-    packet.effect_type = effect_type;
-
-    building_vector_iterate(get_buildings_with_effect(effect_type),
-                           building) {
-      int dummy_type, dummy_range;
-      bool dummy_survives;
-
-      packet.id = *building;
-
-      effect_list_iterate(get_building_effects(*building, effect_type),
-                         peffect) {
-       packet.range = peffect->range;
-       packet.survives = peffect->survives;
-        packet.eff_value = peffect->value;
-       packet.req_type = peffect->req.type;
+  if (packet->effect_id != effect_list_size(ruleset_cache.tracker) - 1) {
+    freelog(LOG_ERROR, "Bug in recv_ruleset_effect_req.");
+  } else {
+    struct effect *peffect = effect_list_get(ruleset_cache.tracker, -1);
+    struct requirement req, *preq;
 
-       if (peffect->group) {
-         packet.group_id = peffect->group->id;
-       } else {
-         packet.group_id = -1;
-       }
+    req = req_from_values(packet->source_type, packet->range, packet->survives,
+       packet->source_value);
 
-       req_get_values(&peffect->req, &dummy_type,
-                      &dummy_range, &dummy_survives, &packet.req_value);
+    preq = fc_malloc(sizeof(*preq));
+    *preq = req;
 
-       lsend_packet_ruleset_cache_effect(dest, &packet);
-      } effect_list_iterate_end;
-    } building_vector_iterate_end;
+    effect_req_append(peffect, packet->neg, preq);
   }
 }
 
@@ -559,8 +420,50 @@
 **************************************************************************/
 void send_ruleset_cache(struct conn_list *dest)
 {
-  send_ruleset_cache_groups(dest);
-  send_ruleset_cache_effects(dest);
+  unsigned id = 0;
+
+  effect_list_iterate(ruleset_cache.tracker, peffect) {
+    struct packet_ruleset_effect packet;
+
+    packet.effect_type = peffect->type;
+    packet.effect_value = peffect->value;
+
+    lsend_packet_ruleset_effect(dest, &packet);
+
+    requirement_list_iterate(peffect->reqs, preq) {
+      struct packet_ruleset_effect_req packet;
+      int type, range, value;
+      bool survives;
+
+      req_get_values(preq, &type, &range, &survives, &value);
+      packet.effect_id = id;
+      packet.neg = FALSE;
+      packet.source_type = type;
+      packet.source_value = value;
+      packet.range = range;
+      packet.survives = survives;
+
+      lsend_packet_ruleset_effect_req(dest, &packet);
+    } requirement_list_iterate_end;
+
+    requirement_list_iterate(peffect->nreqs, preq) {
+      struct packet_ruleset_effect_req packet;
+      int type, range, value;
+      bool survives;
+
+      req_get_values(preq, &type, &range, &survives, &value);
+      packet.effect_id = id;
+      packet.neg = TRUE;
+      packet.source_type = type;
+      packet.source_value = value;
+      packet.range = range;
+      packet.survives = survives;
+
+      lsend_packet_ruleset_effect_req(dest, &packet);
+    } requirement_list_iterate_end;
+
+    id++;
+  } effect_list_iterate_end;
 }
 
 /**************************************************************************
@@ -574,13 +477,19 @@
 {
   /* FIXME: this just returns the first building. it should return the best
    * building instead. */
-  building_vector_iterate(get_buildings_with_effect(effect_type), pbldg) {
-    if (can_player_build_improvement(pplayer, *pbldg)
-       && !improvement_obsolete(pplayer, *pbldg)
-       && is_improvement(*pbldg)) {
-      return *pbldg;
-    }
-  } building_vector_iterate_end;
+  effect_list_iterate(get_effects(effect_type), peffect) {
+    requirement_list_iterate(peffect->reqs, preq) {
+      if (preq->source.type == REQ_BUILDING) {
+       Impr_Type_id id = preq->source.value.building;
+
+       if (can_player_build_improvement(pplayer, id)
+           && !improvement_obsolete(pplayer, id)
+           && is_improvement(id)) {
+         return id;
+       }
+      }
+    } requirement_list_iterate_end;
+  } effect_list_iterate_end;
   return B_LAST;
 }
 
@@ -589,9 +498,13 @@
 **************************************************************************/
 Impr_Type_id get_building_for_effect(enum effect_type effect_type)
 {
-  building_vector_iterate(get_buildings_with_effect(effect_type), pbldg) {
-    return *pbldg;
-  } building_vector_iterate_end;
+  effect_list_iterate(get_effects(effect_type), peffect) {
+    requirement_list_iterate(peffect->reqs, preq) {
+      if (preq->source.type == REQ_BUILDING) {
+       return preq->source.value.building;
+      }
+    } requirement_list_iterate_end;
+  } effect_list_iterate_end;
   return B_LAST;
 }
 
@@ -605,65 +518,86 @@
 **************************************************************************/
 bool building_has_effect(Impr_Type_id id, enum effect_type effect)
 {
-  return (effect_list_size(get_building_effects(id, effect)) > 0);
-}
+  struct req_source source;
+  struct effect_list *plist;
 
-/**************************************************************************
-  Is the effect from the source building redundant on the given target
-  (i.e. are its effects replaced by other sources in the group)?
+  source.type = REQ_BUILDING;
+  source.value.building = id;
 
-  target gives the type of the target
-  (player,pcity,building) gives the exact target
-  source is the source type of the effect
-  peffect is the exact effect
-**************************************************************************/
-static bool is_effect_redundant(enum target_type target,
-                               const struct player *target_player,
-                               const struct city *target_city,
-                               Impr_Type_id target_building,
-                               Impr_Type_id source,
-                               const struct effect *peffect)
-{
-  if (!peffect->group) {
-    /* No group: the effect can't be redundant. */
+  plist = get_req_source_effects(&source);
+
+  if (!plist) {
     return FALSE;
   }
 
-  /* If there is more than one building in the same effects "group", then
-   * only the first one that exists can be active. */
-  effect_group_element_list_iterate(peffect->group->elements, elt) {
-    if (elt->source_building == source) {
-      return FALSE;
-    } else {
-      if (count_buildings_in_range(target, target_player, target_city,
-                                  target_building, elt->range,
-                                  elt->survives, elt->source_building) > 0) {
-       /* The effect from this source in the group makes peffect
-        * redundant.  Note this causes the redundancy even if the
-        * elt->source_building has no effects actually in the group! */
-       return TRUE;
-      }
+  effect_list_iterate(plist, peffect) {
+    if (peffect->type == effect) {
+      return TRUE;
     }
-  } effect_group_element_list_iterate_end;
+  } effect_list_iterate_end;
+  return FALSE;
+}
 
+/**************************************************************************
+  Return TRUE iff any of the disabling requirements for this effect are
+  active (an effect is active if all of its enabling requirements and
+  none of its disabling ones are active).
+**************************************************************************/
+bool is_effect_disabled(enum target_type target,
+                       const struct player *target_player,
+                       const struct city *target_city,
+                       Impr_Type_id target_building,
+                       const struct tile *target_tile,
+                       const struct effect *peffect)
+{
+  requirement_list_iterate(peffect->nreqs, preq) {
+    if (is_req_active(target, target_player, target_city, target_building,
+                     target_tile, preq)) {
+      return TRUE;
+    }
+  } requirement_list_iterate_end;
   return FALSE;
 }
 
 /**************************************************************************
-  Checks the requirements of the effect to see if it is active on the
-  given target. (If the requirements are not met the effect should be
-  ignored.)
-**************************************************************************/
-static bool are_effect_reqs_active(enum target_type target,
-                                  const struct player *target_player,
-                                  const struct city *target_city,
-                                  Impr_Type_id target_building,
-                                  const struct tile *target_tile,
-                                  Impr_Type_id source,
-                                  const struct effect *peffect)
+  Return TRUE iff any of the disabling requirements for this effect are
+  active (an effect is active if all of its enabling requirements and
+  none of its disabling ones are active).
+**************************************************************************/
+static bool is_effect_enabled(enum target_type target,
+                             const struct player *target_player,
+                             const struct city *target_city,
+                             Impr_Type_id target_building,
+                             const struct tile *target_tile,
+                             const struct effect *peffect)
+{
+  requirement_list_iterate(peffect->reqs, preq) {
+    if (!is_req_active(target, target_player, target_city, target_building,
+                      target_tile, preq)) {
+      return FALSE;
+    }
+  } requirement_list_iterate_end;
+  return TRUE;
+}
+
+/**************************************************************************
+  Is the effect active at a certain target (player, city or building)?
+
+  This checks whether an effect's requirements are met.
+
+  target gives the type of the target
+  (player,city,building,tile) give the exact target
+  peffect gives the exact effect value
+**************************************************************************/
+static bool is_effect_active(enum target_type target,
+                            const struct player *plr,
+                            const struct city *pcity,
+                            Impr_Type_id building,
+                            const struct tile *ptile,
+                            const struct effect *peffect)
 {
-  return is_req_active(target, target_player, target_city, target_building,
-                      target_tile, &peffect->req);
+  return is_effect_enabled(target, plr, pcity, building, ptile, peffect)
+    && !is_effect_disabled(target, plr, pcity, building, ptile, peffect);
 }
 
 /**************************************************************************
@@ -685,41 +619,21 @@
                      const struct tile *target_tile,
                      Impr_Type_id source, const struct effect *peffect)
 {
-  if (is_effect_redundant(target, target_player, target_city,
-                         target_building, source, peffect)) {
-    return FALSE;
-  }
-  return are_effect_reqs_active(target, target_player, target_city,
-                               target_building, target_tile,
-                               source, peffect);
-}
-
-/**************************************************************************
-  Is the effect from the source building active at a certain target (player,
-  city or building)?
-
-  This checks whether the source exists, whether it is made redundant by
-  another element in its group, and if its requirements are met.
-
-  target gives the type of the target
-  (player,city,building,tile) give the exact target
-  source gives the source type of the effect
-  peffect gives the exact effect value
-**************************************************************************/
-static bool is_effect_active(enum target_type target,
-                            const struct player *plr,
-                            const struct city *pcity,
-                            Impr_Type_id building,
-                            const struct tile *ptile,
-                            Impr_Type_id source,
-                            const struct effect *peffect)
-{
-  if (count_buildings_in_range(target, plr, pcity, building, peffect->range,
-                              peffect->survives, source) == 0) {
+  if (is_effect_disabled(target, target_player, target_city,
+                        target_building, target_tile, peffect)) {
     return FALSE;
   }
-  return is_effect_useful(target, plr, pcity, building,
-                         ptile, source, peffect);
+  requirement_list_iterate(peffect->reqs, preq) {
+    if (preq->source.type == REQ_BUILDING
+       && preq->source.value.building == source) {
+      continue;
+    }
+    if (!is_req_active(target, target_player, target_city, target_building,
+                      target_tile, preq)) {
+      return FALSE;
+    }
+  } requirement_list_iterate_end;
+  return TRUE;
 }
 
 /**************************************************************************
@@ -728,58 +642,29 @@
 **************************************************************************/
 bool is_building_replaced(const struct city *pcity, Impr_Type_id building)
 {
-  bool groups_present = FALSE;
+  struct req_source source;
+  struct effect_list *plist;
 
-  /* A building that has no effects is never redundant. */
-  effect_type_vector_iterate(get_building_effect_types(building), ptype) {
-    effect_list_iterate(get_building_effects(building, *ptype), peffect) {
-      /* We use TARGET_BUILDING as the lowest common denominator.  Note that
-       * the building is its own target - but whether this is actually
-       * checked depends on the range of the effect. */
-      if (!is_effect_redundant(TARGET_BUILDING, city_owner(pcity), pcity,
-                              building, building, peffect)) {
-       return FALSE;
-      }
-      if (peffect->group) {
-       groups_present = TRUE;
-      }
-    } effect_list_iterate_end;
-  } effect_type_vector_iterate_end;
-
-  return groups_present;
-}
+  source.type = REQ_BUILDING;
+  source.value.building = building;
 
-/**************************************************************************
-  Get the total value, for one effect type, of one source building type on
-  the given target.
+  plist = get_req_source_effects(&source);
 
-  target gives the type of the target
-  (player,city,building,tile) give the exact target
-  source gives the source type of the effect
-  effect_type gives the effect type to be considered
-**************************************************************************/
-static int get_effect_value(enum target_type target,
-                           const struct player *target_player,
-                           const struct city *target_city,
-                           Impr_Type_id target_building,
-                           const struct tile *target_tile,
-                           Impr_Type_id source,
-                           enum effect_type effect_type)
-{
-  int value = 0;
+  /* A building that has no effects is never redundant. */
+  if (!plist) {
+    return FALSE;
+  }
 
-  /* Loop over all effects of this type provided by the given source. */
-  effect_list_iterate(get_building_effects(source, effect_type), peffect) {
-    /* For each effect, see if it is active. */
-    if (is_effect_active(target, target_player, target_city,
-                        target_building, target_tile,
-                        source, peffect)) {
-      /* And if so add on the value. */
-      value += peffect->value;
+  effect_list_iterate(plist, peffect) {
+    /* We use TARGET_BUILDING as the lowest common denominator.  Note that
+     * the building is its own target - but whether this is actually
+     * checked depends on the range of the effect. */
+    if (!is_effect_disabled(TARGET_BUILDING, city_owner(pcity), pcity,
+                           building, NULL, peffect)) {
+      return FALSE;
     }
   } effect_list_iterate_end;
-
-  return value;
+  return TRUE;
 }
 
 /**************************************************************************
@@ -794,7 +679,7 @@
   The returned vector must be freed (building_vector_free) when the caller
   is done with it.
 **************************************************************************/
-static int get_target_bonus_sources(struct effect_source_vector *sources,
+static int get_target_bonus_effects(struct effect_list *plist,
                                    enum target_type target,
                                    const struct player *target_player,
                                    const struct city *target_city,
@@ -804,31 +689,19 @@
 {
   int bonus = 0;
 
-  if (sources) {
-    effect_source_vector_init(sources);
-  }
-
-  /* Loop over all sources that may provide this effect. */
-  building_vector_iterate(get_buildings_with_effect(effect_type), pbldg) {
-    int value;
-
-    /* And for each source, add on the amount of effect provided by it. */
-    value = get_effect_value(target, target_player, target_city,
-                            target_building, target_tile,
-                            *pbldg, effect_type);
-    bonus += value;
-
-    if (sources) {
-      struct effect_source e;
-
-      e.building = *pbldg;
-      e.effect_value = value;
+  /* Loop over all effects of this type. */
+  effect_list_iterate(get_effects(effect_type), peffect) {
+    /* For each effect, see if it is active. */
+    if (is_effect_active(target, target_player, target_city,
+                        target_building, target_tile, peffect)) {
+      /* And if so add on the value. */
+      bonus += peffect->value;
 
-      if (value != 0) {
-       effect_source_vector_append(sources, &e);
+      if (plist) {
+       effect_list_append(plist, peffect);
       }
     }
-  } building_vector_iterate_end;
+  } effect_list_iterate_end;
 
   return bonus;
 }
@@ -839,8 +712,8 @@
 int get_player_bonus(const struct player *pplayer,
                     enum effect_type effect_type)
 {
-  return get_target_bonus_sources(NULL, TARGET_PLAYER,
-                                 pplayer, NULL, B_LAST, NULL,
+  return get_target_bonus_effects(NULL, TARGET_PLAYER,
+                                 pplayer, NULL, B_LAST, NULL,
                                  effect_type);
 }
 
@@ -849,7 +722,7 @@
 **************************************************************************/
 int get_city_bonus(const struct city *pcity, enum effect_type effect_type)
 {
-  return get_target_bonus_sources(NULL, TARGET_CITY,
+  return get_target_bonus_effects(NULL, TARGET_CITY,
                                  city_owner(pcity), pcity, B_LAST, NULL,
                                  effect_type);
 }
@@ -860,8 +733,8 @@
 int get_city_tile_bonus(const struct city *pcity, const struct tile *ptile,
                        enum effect_type effect_type)
 {
-  return get_target_bonus_sources(NULL, TARGET_CITY,
-                                 city_owner(pcity), pcity, B_LAST, ptile,
+  return get_target_bonus_effects(NULL, TARGET_CITY,
+                                 city_owner(pcity), pcity, B_LAST, ptile,
                                  effect_type);
 }
 
@@ -871,8 +744,8 @@
 int get_building_bonus(const struct city *pcity, Impr_Type_id id,
                       enum effect_type effect_type)
 {
-  return get_target_bonus_sources(NULL, TARGET_BUILDING,
-                                 city_owner(pcity), pcity, id, NULL,
+  return get_target_bonus_effects(NULL, TARGET_CITY,
+                                 city_owner(pcity), pcity, id, NULL,
                                  effect_type);
 }
 
@@ -882,10 +755,11 @@
   The returned vector must be freed (building_vector_free) when the caller
   is done with it.
 **************************************************************************/
-int get_player_bonus_sources(struct effect_source_vector *sources,
-    const struct player *pplayer, enum effect_type effect_type)
+int get_player_bonus_effects(struct effect_list *plist,
+                            const struct player *pplayer,
+                            enum effect_type effect_type)
 {
-  return get_target_bonus_sources(sources, TARGET_PLAYER,
+  return get_target_bonus_effects(plist, TARGET_PLAYER,
                                  pplayer, NULL, B_LAST, NULL,
                                  effect_type);
 }
@@ -896,10 +770,11 @@
   The returned vector must be freed (building_vector_free) when the caller
   is done with it.
 **************************************************************************/
-int get_city_bonus_sources(struct effect_source_vector *sources,
-    const struct city *pcity, enum effect_type effect_type)
+int get_city_bonus_effects(struct effect_list *plist,
+                          const struct city *pcity,
+                          enum effect_type effect_type)
 {
-  return get_target_bonus_sources(sources, TARGET_CITY,
+  return get_target_bonus_effects(plist, TARGET_CITY,
                                  city_owner(pcity), pcity, B_LAST, NULL,
                                  effect_type);
 }
@@ -914,19 +789,64 @@
                                   enum effect_type effect_type)
 {
   if (!pcity->is_building_unit) {
-    Impr_Type_id bldg = pcity->currently_building;
+    Impr_Type_id id = pcity->currently_building;
     int power = 0;
 
-    effect_list_iterate(get_building_effects(bldg, effect_type), peffect) {
+    struct req_source source = {
+      .type = REQ_BUILDING,
+      .value.building = id
+    };
+    struct effect_list *plist = get_req_source_effects(&source);
+
+    effect_list_iterate(plist, peffect) {
+      if (peffect->type != effect_type) {
+       continue;
+      }
       if (is_effect_useful(TARGET_BUILDING, city_owner(pcity),
-                          pcity, bldg, NULL, bldg, peffect)) {
+                          pcity, id, NULL, id, peffect)) {
        power += peffect->value;
       }
     } effect_list_iterate_end;
 
     return power;
   }
-
   return 0;
 }
 
+/**************************************************************************
+**************************************************************************/
+void get_effect_req_text(struct effect *peffect, char *buf, size_t buf_len)
+{
+  buf[0] = '\0';
+
+  requirement_list_iterate(peffect->reqs, preq) {
+    struct req_source *psource = &preq->source;
+
+    if (buf[0] != '\0') {
+      mystrlcat(buf, "+", buf_len);
+    }
+
+    switch (psource->type) {
+      case REQ_NONE:
+       break;
+      case REQ_TECH:
+       mystrlcat(buf, advances[psource->value.tech].name, buf_len);
+       break;
+      case REQ_GOV:
+       mystrlcat(buf, get_government_name(psource->value.gov), buf_len);
+       break;
+      case REQ_BUILDING:
+       mystrlcat(buf, get_improvement_name(psource->value.building), buf_len);
+       break;
+      case REQ_SPECIAL:
+       mystrlcat(buf, get_special_name(psource->value.special), buf_len);
+       break;
+      case REQ_TERRAIN:
+       mystrlcat(buf, get_terrain_name(psource->value.terrain), buf_len);
+       break;
+      case REQ_LAST:
+       break;
+    }
+  } requirement_list_iterate_end;
+}
+
Index: common/effects.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.h,v
retrieving revision 1.13
diff -u -r1.13 effects.h
--- common/effects.h    17 Dec 2004 08:21:20 -0000      1.13
+++ common/effects.h    31 Jan 2005 18:20:56 -0000
@@ -112,53 +112,27 @@
 enum effect_type effect_type_from_str(const char *str);
 const char *effect_type_name(enum effect_type effect_type);
 
-/* A building_vector is an array of building types. */
-#define SPECVEC_TAG building
-#define SPECVEC_TYPE Impr_Type_id
-#include "specvec.h"
-#define building_vector_iterate(vector, pbldg) \
-  TYPED_VECTOR_ITERATE(Impr_Type_id, vector, pbldg)
-#define building_vector_iterate_end  VECTOR_ITERATE_END
-
-/* An effect_type_vector is an array of effect types. */
-#define SPECVEC_TAG effect_type
-#define SPECVEC_TYPE enum effect_type
-#include "specvec.h"
-#define effect_type_vector_iterate(vector, ptype) \
-  TYPED_VECTOR_ITERATE(enum effect_type, vector, ptype)
-#define effect_type_vector_iterate_end VECTOR_ITERATE_END
-
-struct effect_group;
-
 /* An effect is provided by a source.  If the source is present, and the
  * other conditions (described below) are met, the effect will be active.
- * Note the difference between effect and effect_type.  The effect doesn't
- * give an effect_type because all effects in an effect_vector will be of
- * the same type. */
+ * Note the difference between effect and effect_type. */
 struct effect {
-  /* The range the effect applies to, relative to the source.  For instance
-   * if the source is a building an effect with range "city" will apply to
-   * everything in that city. */
-  enum req_range range;
+  enum effect_type type;
 
   /* The "value" of the effect.  The meaning of this varies between
    * effects.  When get_xxx_bonus() is called the value of all applicable
    * effects will be summed up. */
   int value;
 
-  /* The group this effect is in.  If more than one source in the group
-   * provides the effect, only one will be active. */
-  struct effect_group *group;
-
-  /* If true, this effect will survive even if its source is destroyed. */
-  bool survives;
-
-  /* An effect can have a single requirement.  The effect will only be
-   * active if this requirement is met.  The req is one of several types. */
-  struct requirement req;
+  /* An effect can have multiple requirements.  The effect will only be
+   * active if all of these requirement are met. */
+  struct requirement_list *reqs;
+
+  /* An effect can have multiple negated requirements.  The effect will
+   * only be active if none of these requirements are met. */
+  struct requirement_list *nreqs;
 };
 
-/* An effect_vector is an array of effects. */
+/* An effect_list is a list of effects. */
 #define SPECLIST_TAG effect
 #define SPECLIST_TYPE struct effect
 #include "speclist.h"
@@ -166,35 +140,22 @@
   TYPED_LIST_ITERATE(struct effect, effect_list, peffect)
 #define effect_list_iterate_end LIST_ITERATE_END
 
-/* This struct contains a source building along with the effect value.  It is
- * primarily useful for get_city_bonus_sources(). */
-struct effect_source {
-  Impr_Type_id building;
-  int effect_value;
-};
-#define SPECVEC_TAG effect_source
-#define SPECVEC_TYPE struct effect_source
-#include "specvec.h"
-#define effect_source_vector_iterate(vector, psource) \
-  TYPED_VECTOR_ITERATE(struct effect_source, vector, psource)
-#define effect_source_vector_iterate_end VECTOR_ITERATE_END
+struct effect *effect_new(enum effect_type type, int value);
+void effect_req_append(struct effect *peffect, bool neg,
+                      struct requirement *preq);
+
+void get_effect_req_text(struct effect *peffect, char *buf, size_t buf_len);
 
 /* ruleset cache creation and communication functions */
+struct packet_ruleset_effect;
+struct packet_ruleset_effect_req;
+
 void ruleset_cache_init(void);
 void ruleset_cache_free(void);
-void ruleset_cache_add(Impr_Type_id source, enum effect_type effect_type,
-                      enum req_range range, bool survives, int eff_value,
-                      struct requirement *req,
-                      int group_id);
+void recv_ruleset_effect(struct packet_ruleset_effect *packet);
+void recv_ruleset_effect_req(struct packet_ruleset_effect_req *packet);
 void send_ruleset_cache(struct conn_list *dest);
 
-/* equivalent effect group */
-struct effect_group *effect_group_new(const char *name);
-void effect_group_add_element(struct effect_group *group,
-                             Impr_Type_id source_building,
-                             enum req_range range, bool survives);
-int find_effect_group_id(const char *name);
-
 bool is_effect_useful(enum target_type target,
                      const struct player *target_player,
                      const struct city *target_pcity,
@@ -213,13 +174,17 @@
                       enum effect_type effect_type);
 
 /* miscellaneous auxiliary effects functions */
-struct effect_list *get_building_effects(Impr_Type_id building,
-                                        enum effect_type effect_type);
-struct effect_type_vector *get_building_effect_types(Impr_Type_id building);
+struct effect_list *get_req_source_effects(struct req_source *psource);
+bool is_effect_disabled(enum target_type target,
+                       const struct player *target_player,
+                       const struct city *target_city,
+                       Impr_Type_id target_building,
+                       const struct tile *target_tile,
+                       const struct effect *peffect);
 
-int get_player_bonus_sources(struct effect_source_vector *sources,
+int get_player_bonus_effects(struct effect_list *plist,
     const struct player *pplayer, enum effect_type effect_type);
-int get_city_bonus_sources(struct effect_source_vector *sources,
+int get_city_bonus_effects(struct effect_list *plist,
     const struct city *pcity, enum effect_type effect_type);
 
 bool building_has_effect(Impr_Type_id building,
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.91
diff -u -r1.91 packets.def
--- common/packets.def  29 Jan 2005 17:58:18 -0000      1.91
+++ common/packets.def  31 Jan 2005 18:20:56 -0000
@@ -181,7 +181,7 @@
 type DIRECTION         = uint8(enum direction8)
 type ORDERS            = uint8(enum unit_orders)
 type SSET_TYPE         = uint8(enum sset_type)
-type REQ_TYPE          = uint8(enum req_type)
+type REQ_TYPE          = uint8(enum req_source_type)
 type REQ_RANGE         = uint8(enum req_range)
 type EFFECT_TYPE       = uint8(enum effect_type)
 
@@ -1266,23 +1266,19 @@
 
 /************** Effects hash packets **********************/
 
-PACKET_RULESET_CACHE_GROUP=120;sc,lsend
-  STRING name[MAX_LEN_NAME];
-
-  UINT8 num_elements;
-  IMPROVEMENT source_buildings[255:num_elements];
-  REQ_RANGE ranges[255:num_elements];
-  BOOL survives[255:num_elements];
+PACKET_RULESET_EFFECT=122;sc,lsend
+  EFFECT_TYPE effect_type;
+  SINT32 effect_value;
 end
 
-PACKET_RULESET_CACHE_EFFECT=121;sc,lsend
-  IMPROVEMENT id;
-  EFFECT_TYPE effect_type;
+PACKET_RULESET_EFFECT_REQ=123;sc,lsend
+  UINT32 effect_id;
+  BOOL neg;
+       
+  REQ_TYPE source_type;
+  SINT32 source_value;
+
   REQ_RANGE range;
   BOOL survives;
-  SINT32 eff_value;
-  REQ_TYPE req_type;
-  SINT32 req_value;
-  SINT32 group_id;
 end
 
Index: common/requirements.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.c,v
retrieving revision 1.4
diff -u -r1.4 requirements.c
--- common/requirements.c       19 Dec 2004 16:47:09 -0000      1.4
+++ common/requirements.c       31 Jan 2005 18:20:56 -0000
@@ -25,9 +25,9 @@
 #include "map.h"
 #include "requirements.h"
 
-/* Names of requirement types.  These must correspond to enum req_type in
+/* Names of source types.  These must correspond to enum req_source_type in
  * requirements.h.  Do not change these unless you know what you're doing! */
-static const char *req_type_names[] = {
+static const char *req_source_type_names[] = {
   "None",
   "Tech",
   "Gov",
@@ -67,86 +67,63 @@
   return REQ_RANGE_LAST;
 }
 
-/****************************************************************************
-  Parse a requirement type and value string into a requrement structure.
-  Returns REQ_LAST on error.  Passing in a NULL type is considered REQ_NONE
-  (not an error).
+/**************************************************************************
+  Parse a requirement type and value string into a requirement source
+  structure.  Passing in a NULL type is considered REQ_NONE (not an error).
 
   Pass this some values like "Building", "Factory".
-****************************************************************************/
-struct requirement req_from_str(const char *type,
-                               const char *range, bool survives,
-                               const char *value)
+**************************************************************************/
+struct req_source req_source_from_str(const char *type, const char *value)
 {
-  struct requirement req;
+  struct req_source source;
   const struct government *pgov;
 
-  assert(ARRAY_SIZE(req_type_names) == REQ_LAST);
+  assert(ARRAY_SIZE(req_source_type_names) == REQ_LAST);
   if (type) {
-    for (req.type = 0; req.type < ARRAY_SIZE(req_type_names); req.type++) {
-      if (0 == mystrcasecmp(req_type_names[req.type], type)) {
+    for (source.type = 0;
+        source.type < ARRAY_SIZE(req_source_type_names);
+        source.type++) {
+      if (0 == mystrcasecmp(req_source_type_names[source.type], type)) {
        break;
       }
     }
   } else {
-    req.type = REQ_NONE;
-  }
-
-  /* Scan the range string to find the range.  If no range is given a
-   * default fallback is used rather than giving an error. */
-  req.range = req_range_from_str(range);
-  if (req.range == REQ_RANGE_LAST) {
-    switch (req.type) {
-    case REQ_NONE:
-    case REQ_LAST:
-      break;
-    case REQ_BUILDING:
-    case REQ_SPECIAL:
-    case REQ_TERRAIN:
-      req.range = REQ_RANGE_CITY;
-      break;
-    case REQ_GOV:
-    case REQ_TECH:
-      req.range = REQ_RANGE_PLAYER;
-      break;
-    }
+    source.type = REQ_NONE;
   }
 
-  req.survives = survives;
-
-  /* Finally scan the value string based on the type of the req. */
-  switch (req.type) {
+  /* Finally scan the value string based on the type of the source. */
+  switch (source.type) {
   case REQ_NONE:
-    return req;
+    return source;
   case REQ_TECH:
-    req.value.tech = find_tech_by_name(value);
-    if (req.value.tech != A_LAST) {
-      return req;
+    source.value.tech = find_tech_by_name(value);
+    if (source.value.tech != A_LAST) {
+      return source;
     }
     break;
   case REQ_GOV:
     pgov = find_government_by_name(value);
     if (pgov != NULL) {
-      req.value.gov = pgov->index;
-      return req;
+      source.value.gov = pgov->index;
+      return source;
     }
     break;
   case REQ_BUILDING:
-    req.value.building = find_improvement_by_name(value);
-    if (req.value.building != B_LAST) {
-      return req;
+    source.value.building = find_improvement_by_name(value);
+    if (source.value.building != B_LAST) {
+      return source;
     }
     break;
   case REQ_SPECIAL:
-    req.value.special = get_special_by_name(value);
-    if (req.value.special != S_NO_SPECIAL) {
-      return req;
+    source.value.special = get_special_by_name(value);
+    if (source.value.special != S_NO_SPECIAL) {
+      return source;
     }
     break;
   case REQ_TERRAIN:
-    req.value.terrain = get_terrain_by_name(value);
-    if (req.value.terrain != T_UNKNOWN) {
-      return req;
+    source.value.terrain = get_terrain_by_name(value);
+    if (source.value.terrain != T_UNKNOWN) {
+      return source;
     }
     break;
   case REQ_LAST:
@@ -154,39 +131,74 @@
   }
 
   /* If we reach here there's been an error. */
-  req.type = REQ_LAST;
-  return req;
+  source.type = REQ_LAST;
+  return source;
 }
 
-/****************************************************************************
-  Return the value of a req as a serializable integer.  This is the opposite
-  of req_set_value.
-****************************************************************************/
-void req_get_values(struct requirement *req,
-                   int *type, int *range, bool *survives, int *value)
+/**************************************************************************
+  Parse some integer values into a req source.  This is for serialization
+  of req sources and is the opposite of req_source_get_values().
+**************************************************************************/
+struct req_source req_source_from_values(int type, int value)
 {
-  *type = req->type;
-  *range = req->range;
-  *survives = req->survives;
+  struct req_source source;
+
+  source.type = type;
+
+  switch (source.type) {
+  case REQ_NONE:
+    return source;
+  case REQ_TECH:
+    source.value.tech = value;
+    return source;
+  case REQ_GOV:
+    source.value.gov = value;
+    return source;
+  case REQ_BUILDING:
+    source.value.building = value;
+    return source;
+  case REQ_SPECIAL:
+    source.value.special = value;
+    return source;
+  case REQ_TERRAIN:
+    source.value.terrain = value;
+    return source;
+  case REQ_LAST:
+    return source;
+  }
+
+  source.type = REQ_LAST;
+  assert(0);
+  return source;
+}
+
+/**************************************************************************
+  Look at a req source and return some integer values describing it.  This
+  is for serialization of req sources and is the opposite of
+  req_source_from_values().
+**************************************************************************/
+void req_source_get_values(struct req_source *source, int *type, int *value)
+{
+  *type = source->type;
 
-  switch (req->type) {
+  switch (source->type) {
   case REQ_NONE:
     *value = 0;
     return;
   case REQ_TECH:
-    *value = req->value.tech;
+    *value = source->value.tech;
     return;
   case REQ_GOV:
-    *value = req->value.gov;
+    *value = source->value.gov;
     return;
   case REQ_BUILDING:
-    *value = req->value.building;
+    *value = source->value.building;
     return;
   case REQ_SPECIAL:
-    *value = req->value.special;
+    *value = source->value.special;
     return;
   case REQ_TERRAIN:
-    *value = req->value.terrain;
+    *value = source->value.terrain;
     return;
   case REQ_LAST:
     break;
@@ -197,6 +209,45 @@
 }
 
 /****************************************************************************
+  Parse a requirement type and value string into a requrement structure.
+  Returns REQ_LAST on error.  Passing in a NULL type is considered REQ_NONE
+  (not an error).
+
+  Pass this some values like "Building", "Factory".
+****************************************************************************/
+struct requirement req_from_str(const char *type,
+                               const char *range, bool survives,
+                               const char *value)
+{
+  struct requirement req;
+
+  req.source = req_source_from_str(type, value);
+
+  /* Scan the range string to find the range.  If no range is given a
+   * default fallback is used rather than giving an error. */
+  req.range = req_range_from_str(range);
+  if (req.range == REQ_RANGE_LAST) {
+    switch (req.source.type) {
+    case REQ_NONE:
+    case REQ_LAST:
+      break;
+    case REQ_BUILDING:
+    case REQ_SPECIAL:
+    case REQ_TERRAIN:
+      req.range = REQ_RANGE_CITY;
+      break;
+    case REQ_GOV:
+    case REQ_TECH:
+      req.range = REQ_RANGE_PLAYER;
+      break;
+    }
+  }
+
+  req.survives = survives;
+  return req;
+}
+
+/****************************************************************************
   Set the values of a req from serializable integers.  This is the opposite
   of req_get_values.
 ****************************************************************************/
@@ -205,38 +256,25 @@
 {
   struct requirement req;
 
-  req.type = type;
+  req.source = req_source_from_values(type, value);
   req.range = range;
   req.survives = survives;
-
-  switch (req.type) {
-  case REQ_NONE:
-    return req;
-  case REQ_TECH:
-    req.value.tech = value;
-    return req;
-  case REQ_GOV:
-    req.value.gov = value;
-    return req;
-  case REQ_BUILDING:
-    req.value.building = value;
-    return req;
-  case REQ_SPECIAL:
-    req.value.special = value;
-    return req;
-  case REQ_TERRAIN:
-    req.value.terrain = value;
-    return req;
-  case REQ_LAST:
-    return req;
-  }
-
-  req.type = REQ_LAST;
-  assert(0);
   return req;
 }
 
 /****************************************************************************
+  Return the value of a req as a serializable integer.  This is the opposite
+  of req_set_value.
+****************************************************************************/
+void req_get_values(struct requirement *req,
+                   int *type, int *range, bool *survives, int *value)
+{
+  req_source_get_values(&req->source, type, value);
+  *range = req->range;
+  *survives = req->survives;
+}
+
+/****************************************************************************
   Is this target possible for the range involved?
 
   For instance a city-ranged requirement can't have a player as it's target.
@@ -452,29 +490,34 @@
    * have a REQ_SPECIAL or REQ_TERRAIN may often be passed to this function
    * with a city as their target.  In this case the requirement is simply
    * not met. */
-  switch (req->type) {
+  switch (req->source.type) {
   case REQ_NONE:
     return TRUE;
   case REQ_TECH:
     /* The requirement is filled if the player owns the tech. */
     return (target_player
-           && get_invention(target_player, req->value.tech) == TECH_KNOWN);
+           && get_invention(target_player,
+                            req->source.value.tech) == TECH_KNOWN);
   case REQ_GOV:
     /* The requirement is filled if the player is using the government. */
-    return target_player && (target_player->government == req->value.gov);
+    return (target_player
+           && (target_player->government == req->source.value.gov));
   case REQ_BUILDING:
     /* The requirement is filled if there's at least one of the building
      * in the city.  (This is a slightly nonstandard use of
      * count_sources_in_range.) */
     return (count_buildings_in_range(target, target_player, target_city,
-                                    target_building, REQ_RANGE_CITY, FALSE,
-                                    req->value.building) > 0);
+                                    target_building,
+                                    req->range, req->survives,
+                                    req->source.value.building) > 0);
   case REQ_SPECIAL:
     /* The requirement is filled if the tile has the special. */
-    return target_tile && tile_has_special(target_tile, req->value.special);
+    return (target_tile
+           && tile_has_special(target_tile, req->source.value.special));
   case REQ_TERRAIN:
     /* The requirement is filled if the tile has the terrain. */
-    return target_tile && (target_tile->terrain  == req->value.terrain);
+    return (target_tile
+           && (target_tile->terrain  == req->source.value.terrain));
   case REQ_LAST:
     break;
   }
Index: common/requirements.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/requirements.h,v
retrieving revision 1.2
diff -u -r1.2 requirements.h
--- common/requirements.h       17 Dec 2004 08:21:20 -0000      1.2
+++ common/requirements.h       31 Jan 2005 18:20:56 -0000
@@ -17,9 +17,9 @@
 #include "fc_types.h"
 #include "tech.h"
 
-/* The type of a requirement.  This must correspond to req_type_names[]
+/* The type of a requirement source.  This must correspond to req_type_names[]
  * in requirements.c. */
-enum req_type {
+enum req_source_type {
   REQ_NONE,
   REQ_TECH,
   REQ_GOV,
@@ -49,25 +49,41 @@
   TARGET_BUILDING 
 };
 
+/* A requirement source. */
+struct req_source {
+  enum req_source_type type;            /* source type */
+
+  union {
+    Tech_Type_id tech;                  /* source tech */
+    int gov;                            /* source government */
+    Impr_Type_id building;              /* source building */
+    enum tile_special_type special;     /* source special */
+    Terrain_type_id terrain;            /* source terrain type */
+  } value;                              /* source value */
+};
+
 /* A requirement. This requirement is basically a conditional; it may or
  * may not be active on a target.  If it is active then something happens.
  * For instance units and buildings have requirements to be built, techs
  * have requirements to be researched, and effects have requirements to be
  * active. */
 struct requirement {
-  enum req_type type;                  /* requirement type */
+  struct req_source source;            /* requirement source */
   enum req_range range;                        /* requirement range */
   bool survives; /* set if destroyed sources satisfy the req*/
-
-  union {
-    Tech_Type_id tech;                 /* requirement tech */
-    int gov;                           /* requirement government */
-    Impr_Type_id building;             /* requirement building */
-    enum tile_special_type special;    /* requirement special */
-    Terrain_type_id terrain;           /* requirement terrain type */
-  } value;                             /* requirement value */
 };
 
+#define SPECLIST_TAG requirement
+#define SPECLIST_TYPE struct requirement
+#include "speclist.h"
+#define requirement_list_iterate(req_list, preq) \
+  TYPED_LIST_ITERATE(struct requirement, req_list, preq)
+#define requirement_list_iterate_end LIST_ITERATE_END
+
+struct req_source req_source_from_str(const char *type, const char *value);
+struct req_source req_source_from_values(int type, int value);
+void req_source_get_values(struct req_source *source, int *type, int *value);
+
 enum req_range req_range_from_str(const char *str);
 struct requirement req_from_str(const char *type, const char *range,
                                bool survives, const char *value);
Index: data/civ1/effects.ruleset
===================================================================
RCS file: data/civ1/effects.ruleset
diff -N data/civ1/effects.ruleset
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/civ1/effects.ruleset   31 Jan 2005 18:20:56 -0000
@@ -0,0 +1,670 @@
+; Modifying this file:
+; You should not modify this file except to make bugfixes or
+; for other "maintenance".  If you want to make custom changes,
+; you should create a new datadir subdirectory and copy this file
+; into that directory, and then modify that copy.  Then use the
+; command "rulesetdir <mysubdir>" in the server to have freeciv
+; use your new customized file.
+
+; Note that the freeciv AI may not cope well with anything more
+; than minor changes.
+
+[datafile]
+description="Civ1 effects data for Freeciv (approximate)"
+options="1.0"
+
+; /* <-- avoid gettext warnings
+; */ <-- avoid gettext warnings
+
+[effect_aqueduct]
+name   = "Size_Unlimit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+    }
+
+[effect_bank]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_bank_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_barracks]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_1]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_2]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_ii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_ii_1]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_ii_2]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_iii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_barracks_iii_1]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_barracks_iii_2]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_cathedral]
+name   = "Make_Content"
+value  = 4
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cathedral", "City"
+    }
+
+[effect_city_walls]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_city_walls_1]
+name   = "Sea_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_city_walls_2]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+
+[effect_colosseum]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_courthouse]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_factory]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+    }
+
+[effect_granary]
+name   = "Growth_Food"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Granary", "City"
+    }
+
+[effect_hydro_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_1]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_library]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+    }
+
+[effect_marketplace]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_marketplace_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_mass_transit]
+name   = "Pollu_Pop_Pct"
+value  = -100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mass Transit", "City"
+    }
+
+[effect_mfg_plant]
+name   = "Prod_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+    }
+
+[effect_nuclear_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_1]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_palace]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_2]
+name   = "Spy_Resistant"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_3]
+name   = "No_Incite"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_4]
+name   = "Capital_City"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_power_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_recycling_center]
+name   = "Pollu_Prod_Pct"
+value  = -66
+reqs   =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_sdi_defense]
+name   = "Nuke_Proof"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_space_component]
+name   = "SS_Component"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Component", "City"
+    }
+
+[effect_space_module]
+name   = "SS_Module"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Module", "City"
+    }
+
+[effect_space_structural]
+name   = "SS_Structural"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Structural", "City"
+    }
+
+[effect_temple]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+    }
+
+[effect_temple_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Mysticism", "Player"
+      "Building", "Temple", "City"
+    }
+
+[effect_university]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "University", "City"
+    }
+
+[effect_apollo_program]
+name   = "Reveal_Cities"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Apollo Program", "Player"
+    }
+
+[effect_apollo_program_1]
+name   = "Enable_Space"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Apollo Program", "World", 1
+    }
+
+[effect_colossus]
+name   = "Trade_Inc_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colossus", "City"
+    }
+
+[effect_copernicus_observatory]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_copernicus_observatory_1]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "University", "City"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_copernicus_observatory_2]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_cure_for_cancer]
+name   = "Force_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cure For Cancer", "Player"
+    }
+
+[effect_darwins_voyage]
+name   = "Give_Imm_Tech"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Darwin's Voyage", "Player"
+    }
+
+[effect_great_library]
+name   = "Tech_Parasite"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Library", "Player"
+    }
+
+[effect_great_wall]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_great_wall_1]
+name   = "Sea_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_hanging_gardens]
+name   = "Make_Happy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "Player"
+    }
+
+[effect_hoover_dam]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Continent"
+    }
+
+[effect_hoover_dam_1]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Continent"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_isaac_newtons_college]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "Isaac Newton's College", "City"
+    }
+
+[effect_isaac_newtons_college_1]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "University", "City"
+      "Building", "Isaac Newton's College", "Player"
+    }
+
+[effect_js_bachs_cathedral]
+name   = "Force_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "J.S. Bach's Cathedral", "Continent"
+    }
+
+[effect_lighthouse]
+name   = "Sea_Move"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_magellans_expedition]
+name   = "Sea_Move"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Magellan's Expedition", "Player"
+    }
+
+[effect_manhattan_project]
+name   = "Enable_Nuke"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Manhattan Project", "World", 1
+    }
+
+[effect_michelangelos_chapel]
+name   = "Make_Content"
+value  = 4
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cathedral", "City"
+      "Building", "Michelangelo's Chapel", "City"
+    }
+
+[effect_oracle]
+name   = "Make_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+      "Building", "Oracle", "Player"
+    }
+
+[effect_pyramids]
+name   = "Any_Government"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Pyramids", "Player"
+    }
+
+[effect_pyramids_1]
+name   = "No_Anarchy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Pyramids", "Player"
+    }
+
+[effect_seti_program]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_shakespeares_theatre]
+name   = "No_Unhappy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Shakespeare's Theatre", "City"
+    }
+
+[effect_united_nations]
+name   = "Any_Government"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "United Nations", "Player"
+    }
+
+[effect_united_nations_1]
+name   = "No_Anarchy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "United Nations", "Player"
+    }
+
+[effect_womens_suffrage]
+name   = "Make_Content_Mil_Per"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_capitalization]
+name   = "Prod_To_Gold"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Capitalization", "City"
+    }
+
Index: data/civ2/effects.ruleset
===================================================================
RCS file: data/civ2/effects.ruleset
diff -N data/civ2/effects.ruleset
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/civ2/effects.ruleset   31 Jan 2005 18:20:56 -0000
@@ -0,0 +1,980 @@
+; Modifying this file:
+; You should not modify this file except to make bugfixes or
+; for other "maintenance".  If you want to make custom changes,
+; you should create a new datadir subdirectory and copy this file
+; into that directory, and then modify that copy.  Then use the
+; command "rulesetdir <mysubdir>" in the server to have freeciv
+; use your new customized file.
+
+; Note that the freeciv AI may not cope well with anything more
+; than minor changes.
+
+[datafile]
+description="Civ2 effects data for Freeciv (incomplete)"
+options="1.0"
+
+; /* <-- avoid gettext warnings
+; */ <-- avoid gettext warnings
+
+[effect_airport]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_1]
+name   = "Air_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_2]
+name   = "Airlift"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_aqueduct]
+name   = "Size_Adj"
+value  = 4
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+    }
+
+[effect_bank]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_bank_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_barracks]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_ii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_ii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_iii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_barracks_iii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_cathedral]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_city_walls]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_city_walls_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+
+[effect_coastal_defense]
+name   = "Sea_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Coastal Defense", "City"
+    }
+
+[effect_colosseum]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_colosseum_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Electricity", "Player"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_courthouse]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_2]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_courthouse_3]
+name   = "Incite_Dist_Pct"
+value  = 75
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_factory]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+    }
+
+[effect_granary]
+name   = "Growth_Food"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Granary", "City"
+    }
+
+[effect_harbour]
+name   = "Food_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Harbour", "City"
+    }
+
+[effect_hydro_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_library]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+    }
+
+[effect_marketplace]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_marketplace_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_mass_transit]
+name   = "Pollu_Pop_Pct"
+value  = -100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mass Transit", "City"
+    }
+
+[effect_mfg_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Mfg. Plant", "City"
+    }
+
+[effect_nuclear_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_offshore_platform]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Offshore Platform", "City"
+    }
+
+[effect_palace]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_2]
+name   = "Spy_Resistant"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_3]
+name   = "No_Incite"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_4]
+name   = "Capital_City"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_police_station]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_police_station_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_port_facility]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_port_facility_1]
+name   = "Sea_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_power_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_power_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_recycling_center]
+name   = "Pollu_Prod_Pct"
+value  = -66
+reqs   =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_research_lab]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "Research Lab", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_sam_battery]
+name   = "Air_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SAM Battery", "City"
+    }
+
+[effect_sdi_defense]
+name   = "Nuke_Proof"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sdi_defense_1]
+name   = "Missile_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sewer_system]
+name   = "Size_Unlimit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+      "Building", "Sewer System", "City"
+    }
+
+[effect_space_component]
+name   = "SS_Component"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Component", "City"
+    }
+
+[effect_space_module]
+name   = "SS_Module"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Module", "City"
+    }
+
+[effect_space_structural]
+name   = "SS_Structural"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Structural", "City"
+    }
+
+[effect_stock_exchange]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_stock_exchange_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_super_highways]
+name   = "Trade_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Road", "City"
+      "Building", "Super Highways", "City"
+    }
+
+[effect_supermarket]
+name   = "Food_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Farmland", "City"
+      "Building", "Supermarket", "City"
+    }
+
+[effect_temple]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+    }
+
+[effect_temple_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Mysticism", "Player"
+      "Building", "Temple", "City"
+    }
+
+[effect_university]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "University", "City"
+    }
+
+[effect_apollo_program]
+name   = "Reveal_Map"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Apollo Program", "Player"
+    }
+
+[effect_apollo_program_1]
+name   = "Enable_Space"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Apollo Program", "World", 1
+    }
+
+[effect_asmiths_trading_co]
+name   = "Upkeep_Free"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "A.Smith's Trading Co.", "Player"
+    }
+
+[effect_colossus]
+name   = "Trade_Inc_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colossus", "City"
+    }
+
+[effect_copernicus_observatory]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_cure_for_cancer]
+name   = "Force_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cure For Cancer", "Player"
+    }
+
+[effect_darwins_voyage]
+name   = "Give_Imm_Tech"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Darwin's Voyage", "Player"
+    }
+
+[effect_great_library]
+name   = "Tech_Parasite"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Library", "Player"
+    }
+
+[effect_great_wall]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_great_wall_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_hanging_gardens]
+name   = "Make_Happy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "Player"
+    }
+
+[effect_hanging_gardens_1]
+name   = "Make_Happy"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "City"
+    }
+
+[effect_hoover_dam]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_isaac_newtons_college]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Isaac Newton's College", "City"
+    }
+
+[effect_js_bachs_cathedral]
+name   = "Force_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "J.S. Bach's Cathedral", "Player"
+    }
+
+[effect_king_richards_crusade]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "King Richard's Crusade", "City"
+    }
+
+[effect_leonardos_workshop]
+name   = "Upgrade_Unit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Leonardo's Workshop", "Player"
+    }
+
+[effect_lighthouse]
+name   = "Sea_Move"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_1]
+name   = "No_Sink_Deep"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_2]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_magellans_expedition]
+name   = "Sea_Move"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Magellan's Expedition", "Player"
+    }
+
+[effect_manhattan_project]
+name   = "Enable_Nuke"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Manhattan Project", "World", 1
+    }
+
+[effect_marco_polos_embassy]
+name   = "Have_Embassies"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marco Polo's Embassy", "Player"
+    }
+
+[effect_michelangelos_chapel]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_oracle]
+name   = "Make_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+      "Building", "Oracle", "Player"
+    }
+
+[effect_pyramids]
+name   = "Growth_Food"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Pyramids", "Player"
+    }
+
+[effect_seti_program]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_shakespeares_theatre]
+name   = "No_Unhappy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Shakespeare's Theatre", "City"
+    }
+
+[effect_statue_of_liberty]
+name   = "Any_Government"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_statue_of_liberty_1]
+name   = "No_Anarchy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_sun_tzus_war_academy]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_sun_tzus_war_academy_1]
+name   = "Land_Vet_Combat"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_united_nations]
+name   = "Unit_Recover"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "United Nations", "Player"
+    }
+
+[effect_womens_suffrage]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_womens_suffrage_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_capitalization]
+name   = "Prod_To_Gold"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Capitalization", "City"
+    }
+
Index: data/default/effects.ruleset
===================================================================
RCS file: data/default/effects.ruleset
diff -N data/default/effects.ruleset
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/default/effects.ruleset        31 Jan 2005 18:20:56 -0000
@@ -0,0 +1,1047 @@
+; Modifying this file:
+; You should not modify this file except to make bugfixes or
+; for other "maintenance".  If you want to make custom changes,
+; you should create a new datadir subdirectory and copy this file
+; into that directory, and then modify that copy.  Then use the
+; command "rulesetdir <mysubdir>" in the server to have freeciv
+; use your new customized file.
+
+; Note that the freeciv AI may not cope well with anything more
+; than minor changes.
+
+[datafile]
+description="Default effects data for Freeciv"
+options="1.0"
+
+; /* <-- avoid gettext warnings
+; */ <-- avoid gettext warnings
+
+[effect_airport]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_1]
+name   = "Air_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_2]
+name   = "Airlift"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_aqueduct]
+name   = "Size_Adj"
+value  = 4
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+    }
+
+[effect_bank]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_bank_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_barracks]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_ii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_ii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_iii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_barracks_iii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_cathedral]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_city_walls]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_city_walls_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+
+[effect_coastal_defense]
+name   = "Sea_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Coastal Defense", "City"
+    }
+
+[effect_colosseum]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_colosseum_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Electricity", "Player"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_courthouse]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_2]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_courthouse_3]
+name   = "Incite_Dist_Pct"
+value  = 75
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_factory]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+    }
+
+[effect_granary]
+name   = "Growth_Food"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Granary", "City"
+    }
+
+[effect_harbour]
+name   = "Food_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Harbour", "City"
+    }
+
+[effect_hydro_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_3]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_library]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+    }
+
+[effect_marketplace]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_marketplace_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_mass_transit]
+name   = "Pollu_Pop_Pct"
+value  = -100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mass Transit", "City"
+    }
+
+[effect_mfg_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Mfg. Plant", "City"
+    }
+
+[effect_nuclear_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_3]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_offshore_platform]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Offshore Platform", "City"
+    }
+
+[effect_palace]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_2]
+name   = "Spy_Resistant"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_3]
+name   = "No_Incite"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_4]
+name   = "Capital_City"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_police_station]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_police_station_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_port_facility]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_port_facility_1]
+name   = "Sea_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_power_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_power_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_recycling_center]
+name   = "Pollu_Prod_Pct"
+value  = -66
+reqs   =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_research_lab]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "Research Lab", "City"
+    }
+
+[effect_research_lab_1]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "University", "City"
+      "Building", "Research Lab", "City"
+    }
+
+[effect_sam_battery]
+name   = "Air_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SAM Battery", "City"
+    }
+
+[effect_sdi_defense]
+name   = "Nuke_Proof"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sdi_defense_1]
+name   = "Missile_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sewer_system]
+name   = "Size_Unlimit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+      "Building", "Sewer System", "City"
+    }
+
+[effect_space_component]
+name   = "SS_Component"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Component", "City"
+    }
+
+[effect_space_module]
+name   = "SS_Module"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Module", "City"
+    }
+
+[effect_space_structural]
+name   = "SS_Structural"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Structural", "City"
+    }
+
+[effect_stock_exchange]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_stock_exchange_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_super_highways]
+name   = "Trade_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Road", "City"
+      "Building", "Super Highways", "City"
+    }
+
+[effect_supermarket]
+name   = "Food_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Farmland", "City"
+      "Building", "Supermarket", "City"
+    }
+
+[effect_temple]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+    }
+
+[effect_temple_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Mysticism", "Player"
+      "Building", "Temple", "City"
+    }
+
+[effect_university]
+name   = "Science_Bonus"
+value  = 150
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "University", "City"
+    }
+
+[effect_apollo_program]
+name   = "Reveal_Map"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Apollo Program", "Player"
+    }
+
+[effect_apollo_program_1]
+name   = "Enable_Space"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Apollo Program", "World", 1
+    }
+
+[effect_asmiths_trading_co]
+name   = "Upkeep_Free"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "A.Smith's Trading Co.", "Player"
+    }
+
+[effect_colossus]
+name   = "Trade_Inc_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colossus", "City"
+    }
+
+[effect_copernicus_observatory]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_cure_for_cancer]
+name   = "Force_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cure For Cancer", "Player"
+    }
+
+[effect_darwins_voyage]
+name   = "Give_Imm_Tech"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Darwin's Voyage", "Player"
+    }
+
+[effect_eiffel_tower]
+name   = "Regen_Reputation"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Eiffel Tower", "Player"
+    }
+
+[effect_eiffel_tower_1]
+name   = "Gain_AI_Love"
+value  = 20
+reqs   =
+    { "type", "name", "range"
+      "Building", "Eiffel Tower", "Player"
+    }
+
+[effect_great_library]
+name   = "Tech_Parasite"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Library", "Player"
+    }
+
+[effect_great_wall]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_great_wall_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_hanging_gardens]
+name   = "Make_Happy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "Player"
+    }
+
+[effect_hanging_gardens_1]
+name   = "Make_Happy"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "City"
+    }
+
+[effect_hoover_dam]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_2]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_hoover_dam_3]
+name   = "Pollu_Prod_Pct"
+value  = -25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_isaac_newtons_college]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "University", "City"
+      "Building", "Isaac Newton's College", "Player"
+    }
+
+[effect_js_bachs_cathedral]
+name   = "Force_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "J.S. Bach's Cathedral", "Player"
+    }
+
+[effect_king_richards_crusade]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "King Richard's Crusade", "City"
+    }
+
+[effect_leonardos_workshop]
+name   = "Upgrade_Unit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Leonardo's Workshop", "Player"
+    }
+
+[effect_lighthouse]
+name   = "Sea_Move"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_1]
+name   = "No_Sink_Deep"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_2]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_magellans_expedition]
+name   = "Sea_Move"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Magellan's Expedition", "Player"
+    }
+
+[effect_manhattan_project]
+name   = "Enable_Nuke"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Manhattan Project", "World", 1
+    }
+
+[effect_marco_polos_embassy]
+name   = "Have_Embassies"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marco Polo's Embassy", "Player"
+    }
+
+[effect_michelangelos_chapel]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_oracle]
+name   = "Make_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+      "Building", "Oracle", "Player"
+    }
+
+[effect_pyramids]
+name   = "Growth_Food"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Pyramids", "Player"
+    }
+
+[effect_seti_program]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Research Lab", "City"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_shakespeares_theatre]
+name   = "No_Unhappy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Shakespeare's Theatre", "City"
+    }
+
+[effect_statue_of_liberty]
+name   = "Any_Government"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_statue_of_liberty_1]
+name   = "No_Anarchy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_sun_tzus_war_academy]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_sun_tzus_war_academy_1]
+name   = "Land_Vet_Combat"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_united_nations]
+name   = "Unit_Recover"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "United Nations", "Player"
+    }
+
+[effect_womens_suffrage]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_womens_suffrage_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_coinage]
+name   = "Prod_To_Gold"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Coinage", "City"
+    }
+
Index: data/history/effects.ruleset
===================================================================
RCS file: data/history/effects.ruleset
diff -N data/history/effects.ruleset
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/history/effects.ruleset        31 Jan 2005 18:20:56 -0000
@@ -0,0 +1,980 @@
+; Modifying this file:
+; You should not modify this file except to make bugfixes or
+; for other "maintenance".  If you want to make custom changes,
+; you should create a new datadir subdirectory and copy this file
+; into that directory, and then modify that copy.  Then use the
+; command "rulesetdir <mysubdir>" in the server to have freeciv
+; use your new customized file.
+
+; Note that the freeciv AI may not cope well with anything more
+; than minor changes.
+
+[datafile]
+description="History effects data for Freeciv"
+options="1.0"
+
+; /* <-- avoid gettext warnings
+; */ <-- avoid gettext warnings
+
+[effect_airport]
+name   = "Air_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_1]
+name   = "Air_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_airport_2]
+name   = "Airlift"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Airport", "City"
+    }
+
+[effect_aqueduct]
+name   = "Size_Adj"
+value  = 4
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+    }
+
+[effect_bank]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_bank_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+      "Building", "Bank", "City"
+    }
+
+[effect_barracks]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks", "City"
+    }
+
+[effect_barracks_ii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_ii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks II", "City"
+    }
+
+[effect_barracks_iii]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_barracks_iii_1]
+name   = "Land_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Barracks III", "City"
+    }
+
+[effect_cathedral]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_cathedral_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Cathedral", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_city_walls]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_city_walls_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "City Walls", "City"
+    }
+
+[effect_coastal_defense]
+name   = "Sea_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Coastal Defense", "City"
+    }
+
+[effect_colosseum]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_colosseum_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Electricity", "Player"
+      "Building", "Colosseum", "City"
+    }
+
+[effect_courthouse]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_courthouse_2]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_courthouse_3]
+name   = "Incite_Dist_Pct"
+value  = 75
+reqs   =
+    { "type", "name", "range"
+      "Building", "Courthouse", "City"
+    }
+
+[effect_factory]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+    }
+
+[effect_granary]
+name   = "Growth_Food"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Granary", "City"
+    }
+
+[effect_harbour]
+name   = "Food_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Harbour", "City"
+    }
+
+[effect_hydro_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_hydro_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hydro Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+    }
+
+[effect_library]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+    }
+
+[effect_marketplace]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_marketplace_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marketplace", "City"
+    }
+
+[effect_mass_transit]
+name   = "Pollu_Pop_Pct"
+value  = -100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mass Transit", "City"
+    }
+
+[effect_mfg_plant]
+name   = "Prod_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Mfg. Plant", "City"
+    }
+
+[effect_nuclear_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_nuclear_plant_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Nuclear Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_offshore_platform]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Terrain", "Ocean", "City"
+      "Building", "Offshore Platform", "City"
+    }
+
+[effect_palace]
+name   = "Corrupt_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_1]
+name   = "Waste_Pct"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_2]
+name   = "Spy_Resistant"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_3]
+name   = "No_Incite"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_palace_4]
+name   = "Capital_City"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Palace", "City"
+    }
+
+[effect_police_station]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_police_station_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Police Station", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_port_facility]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_port_facility_1]
+name   = "Sea_Regen"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Port Facility", "City"
+    }
+
+[effect_power_plant]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_power_plant_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Power Plant", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+      "Building", "Nuclear Plant", "City"
+      "Building", "Hydro Plant", "City"
+    }
+
+[effect_recycling_center]
+name   = "Pollu_Prod_Pct"
+value  = -66
+reqs   =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_research_lab]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "Research Lab", "City"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_sam_battery]
+name   = "Air_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SAM Battery", "City"
+    }
+
+[effect_sdi_defense]
+name   = "Nuke_Proof"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sdi_defense_1]
+name   = "Missile_Defend"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "SDI Defense", "City"
+    }
+
+[effect_sewer_system]
+name   = "Size_Unlimit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Aqueduct", "City"
+      "Building", "Sewer System", "City"
+    }
+
+[effect_space_component]
+name   = "SS_Component"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Component", "City"
+    }
+
+[effect_space_module]
+name   = "SS_Module"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Module", "City"
+    }
+
+[effect_space_structural]
+name   = "SS_Structural"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Space Structural", "City"
+    }
+
+[effect_stock_exchange]
+name   = "Tax_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_stock_exchange_1]
+name   = "Luxury_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Bank", "City"
+      "Building", "Stock Exchange", "City"
+    }
+
+[effect_super_highways]
+name   = "Trade_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Road", "City"
+      "Building", "Super Highways", "City"
+    }
+
+[effect_supermarket]
+name   = "Food_Per_Tile"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Special", "Farmland", "City"
+      "Building", "Supermarket", "City"
+    }
+
+[effect_temple]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+    }
+
+[effect_temple_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Mysticism", "Player"
+      "Building", "Temple", "City"
+    }
+
+[effect_university]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "University", "City"
+    }
+
+[effect_apollo_program]
+name   = "Reveal_Map"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Apollo Program", "Player"
+    }
+
+[effect_apollo_program_1]
+name   = "Enable_Space"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Apollo Program", "World", 1
+    }
+
+[effect_asmiths_trading_co]
+name   = "Upkeep_Free"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "A.Smith's Trading Co.", "Player"
+    }
+
+[effect_colossus]
+name   = "Trade_Inc_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Colossus", "City"
+    }
+
+[effect_copernicus_observatory]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Copernicus' Observatory", "City"
+    }
+
+[effect_cure_for_cancer]
+name   = "Force_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Cure For Cancer", "Player"
+    }
+
+[effect_darwins_voyage]
+name   = "Give_Imm_Tech"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Darwin's Voyage", "Player"
+    }
+
+[effect_great_library]
+name   = "Tech_Parasite"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Library", "Player"
+    }
+
+[effect_great_wall]
+name   = "Land_Defend"
+value  = 200
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_great_wall_1]
+name   = "Unit_No_Lose_Pop"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Great Wall", "Player"
+    }
+
+[effect_hanging_gardens]
+name   = "Make_Happy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "Player"
+    }
+
+[effect_hanging_gardens_1]
+name   = "Make_Happy"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hanging Gardens", "City"
+    }
+
+[effect_hoover_dam]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Factory", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_1]
+name   = "Prod_Bonus"
+value  = 25
+reqs   =
+    { "type", "name", "range"
+      "Building", "Mfg. Plant", "City"
+      "Building", "Hoover Dam", "Player"
+    }
+
+[effect_hoover_dam_2]
+name   = "Pollu_Prod_Pct"
+value  = -50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Hoover Dam", "Player"
+    }
+nreqs  =
+    { "type", "name", "range"
+      "Building", "Recycling Center", "City"
+    }
+
+[effect_isaac_newtons_college]
+name   = "Science_Bonus"
+value  = 100
+reqs   =
+    { "type", "name", "range"
+      "Building", "Isaac Newton's College", "City"
+    }
+
+[effect_js_bachs_cathedral]
+name   = "Force_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "J.S. Bach's Cathedral", "Player"
+    }
+
+[effect_king_richards_crusade]
+name   = "Prod_Add_Tile"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "King Richard's Crusade", "City"
+    }
+
+[effect_leonardos_workshop]
+name   = "Upgrade_Unit"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Leonardo's Workshop", "Player"
+    }
+
+[effect_lighthouse]
+name   = "Sea_Move"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_1]
+name   = "No_Sink_Deep"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_lighthouse_2]
+name   = "Sea_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Lighthouse", "Player"
+    }
+
+[effect_magellans_expedition]
+name   = "Sea_Move"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Magellan's Expedition", "Player"
+    }
+
+[effect_manhattan_project]
+name   = "Enable_Nuke"
+value  = 1
+reqs   =
+    { "type", "name", "range", "survives"
+      "Building", "Manhattan Project", "World", 1
+    }
+
+[effect_marco_polos_embassy]
+name   = "Have_Embassies"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Marco Polo's Embassy", "Player"
+    }
+
+[effect_michelangelos_chapel]
+name   = "Make_Content"
+value  = 3
+reqs   =
+    { "type", "name", "range"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_1]
+name   = "Make_Content"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Theology", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_michelangelos_chapel_2]
+name   = "Make_Content"
+value  = -1
+reqs   =
+    { "type", "name", "range"
+      "Tech", "Communism", "Player"
+      "Building", "Michelangelo's Chapel", "Player"
+    }
+
+[effect_oracle]
+name   = "Make_Content"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "Temple", "City"
+      "Building", "Oracle", "Player"
+    }
+
+[effect_pyramids]
+name   = "Growth_Food"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Pyramids", "Player"
+    }
+
+[effect_seti_program]
+name   = "Science_Bonus"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Library", "City"
+      "Building", "SETI Program", "Player"
+    }
+
+[effect_shakespeares_theatre]
+name   = "No_Unhappy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Shakespeare's Theatre", "City"
+    }
+
+[effect_statue_of_liberty]
+name   = "Any_Government"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_statue_of_liberty_1]
+name   = "No_Anarchy"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Statue of Liberty", "Player"
+    }
+
+[effect_sun_tzus_war_academy]
+name   = "Land_Veteran"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_sun_tzus_war_academy_1]
+name   = "Land_Vet_Combat"
+value  = 50
+reqs   =
+    { "type", "name", "range"
+      "Building", "Sun Tzu's War Academy", "Player"
+    }
+
+[effect_united_nations]
+name   = "Unit_Recover"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Building", "United Nations", "Player"
+    }
+
+[effect_womens_suffrage]
+name   = "Make_Content_Mil"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Republic", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_womens_suffrage_1]
+name   = "Make_Content_Mil"
+value  = 2
+reqs   =
+    { "type", "name", "range"
+      "Gov", "Democracy", "Player"
+      "Building", "Women's Suffrage", "Player"
+    }
+
+[effect_coinage]
+name   = "Prod_To_Gold"
+value  = 1
+reqs   =
+    { "type", "name", "range"
+      "Building", "Coinage", "City"
+    }
+
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.355
diff -u -r1.355 plrhand.c
--- server/plrhand.c    22 Jan 2005 21:12:10 -0000      1.355
+++ server/plrhand.c    31 Jan 2005 18:20:57 -0000
@@ -130,21 +130,21 @@
 void do_tech_parasite_effect(struct player *pplayer)
 {
   int mod;
-  struct effect_source_vector sources;
+  struct effect_list *plist = effect_list_new();
 
   /* Note that two EFT_TECH_PARASITE effects will combine into a single,
    * much worse effect. */
-  if ((mod = get_player_bonus_sources(&sources, pplayer,
+  if ((mod = get_player_bonus_effects(plist, pplayer,
                                      EFT_TECH_PARASITE)) > 0) {
     char buf[512];
 
     buf[0] = '\0';
-    effect_source_vector_iterate(&sources, src) {
+    effect_list_iterate(plist, peffect) {
       if (buf[0] != '\0') {
        sz_strlcat(buf, ", ");
       }
-      sz_strlcat(buf, get_improvement_name(src->building));
-    } effect_source_vector_iterate_end;
+      get_effect_req_text(peffect, buf, sizeof(buf));
+    } effect_list_iterate_end;
 
     tech_type_iterate(i) {
       if (get_invention(pplayer, i) != TECH_KNOWN
@@ -165,7 +165,8 @@
       }
     } tech_type_iterate_end;
   }
-  effect_source_vector_free(&sources);
+  effect_list_unlink_all(plist);
+  effect_list_free(plist);
 }
 
 /****************************************************************************
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.229
diff -u -r1.229 ruleset.c
--- server/ruleset.c    29 Jan 2005 17:58:19 -0000      1.229
+++ server/ruleset.c    31 Jan 2005 18:20:57 -0000
@@ -90,6 +90,7 @@
 static void load_ruleset_terrain(struct section_file *file);
 static void load_ruleset_cities(struct section_file *file);
 static void load_ruleset_nations(struct section_file *file);
+static void load_ruleset_effects(struct section_file *file);
 
 static void load_ruleset_game(void);
 
@@ -1157,57 +1158,6 @@
 
   (void) check_ruleset_capabilities(file, "+1.10.1", filename);
 
-  /* Parse effect source equivalency groups. */
-  sec = secfile_get_secnames_prefix(file, "group_", &nval);
-  for (i = 0; i < nval; i++) {
-    struct effect_group *group;
-    char name[MAX_LEN_NAME];
-
-    item = secfile_lookup_str(file, "%s.name", sec[i]);
-    sz_strlcpy(name, item);
-
-    group = effect_group_new(name);
-
-    for (j = 0;
-        (item = secfile_lookup_str_default(file, NULL,
-                                           "%s.elements%d.building",
-                                           sec[i], j));
-        j++) {
-      Impr_Type_id id;
-      enum req_range range;
-      bool survives;
-
-      if ((id = find_improvement_by_name(item)) == B_LAST) {
-       freelog(LOG_ERROR,
-               /* TRANS: Obscure ruleset error */
-               _("Group %s lists unknown building: \"%s\" (%s)"),
-               name, item, filename);
-       continue;
-      }
-
-      item = secfile_lookup_str_default(file, NULL, "%s.elements%d.range",
-                                       sec[i], j);
-      if (item) {
-       if ((range = req_range_from_str(item)) == REQ_RANGE_LAST) {
-         freelog(LOG_ERROR,
-                 /* TRANS: Obscure ruleset error */
-                 _("Group %s lists bad range: \"%s\" (%s)"),
-                 name, item, filename);
-         continue;
-       }
-      } else {
-       range = REQ_RANGE_CITY;
-      }
-
-      survives
-       = secfile_lookup_bool_default(file, FALSE, "%s.elements%d.survives",
-                                     sec[i], j);
-
-      effect_group_add_element(group, id, range, survives);
-    }
-  }
-  free(sec);
-
   sec = secfile_get_secnames_prefix(file, "building_", &nval);
 
   for (i = 0; i < nval; i++) {
@@ -1279,83 +1229,6 @@
 
     b->sabotage = secfile_lookup_int(file, "%s.sabotage", sec[i]);
 
-    /* Parse building effects and add them to the effects ruleset cache. */
-    {
-      for (j = 0;
-          (item = secfile_lookup_str_default(file, NULL, "%s.effect%d.name",
-                                             sec[i], j));
-          j++) {
-       int value;
-       enum effect_type eff;
-       enum req_range range;
-       bool survives;
-       struct requirement req;
-       char *req_type, *req_value;
-       int equiv;
-
-       if ((eff = effect_type_from_str(item)) == EFT_LAST) {
-         freelog(LOG_ERROR,
-                 /* TRANS: Obscure ruleset error */
-                 _("Building %s lists unknown effect type: \"%s\" (%s)"),
-                 b->name, item, filename);
-         continue;
-       }
-
-       item = secfile_lookup_str_default(file, NULL, "%s.effect%d.range",
-                                         sec[i], j);
-       if (item) {
-         if ((range = req_range_from_str(item)) == REQ_RANGE_LAST) {
-           freelog(LOG_ERROR,
-                   /* TRANS: Obscure ruleset error */
-                   _("Building %s lists bad range: \"%s\" (%s)"),
-                   b->name, item, filename);
-           continue;
-         }
-       } else {
-         range = REQ_RANGE_CITY;
-       }
-
-       survives = secfile_lookup_bool_default(file, FALSE, 
"%s.effect%d.survives",
-                                              sec[i], j);
-
-       value = secfile_lookup_int_default(file, 1, "%s.effect%d.value",
-                                          sec[i], j);
-
-       /* Sometimes the ruleset will have to list "" here. */
-       item = secfile_lookup_str_default(file, "", "%s.effect%d.equiv",
-                                         sec[i], j);
-       if (item[0] != '\0') {
-         if ((equiv = find_effect_group_id(item)) == -1) {
-           freelog(LOG_ERROR,
-                   /* TRANS: Obscure ruleset error */
-                   _("Building %s lists bad effect group: \"%s\" (%s)"),
-                   b->name, item, filename);
-           continue;
-         }
-       } else {
-         equiv = -1;
-       }
-
-       /* Sometimes the ruleset will have to list "" here. */
-       req_type = secfile_lookup_str_default(file, NULL,
-                                             "%s.effect%d.req_type",
-                                             sec[i], j);
-       req_value = secfile_lookup_str_default(file, "", "%s.effect%d.req",
-                                              sec[i], j);
-       req = req_from_str(req_type, "", FALSE, req_value);
-       if (req.type == REQ_LAST) {
-         /* Error.  Log it, clear the req and continue. */
-         freelog(LOG_ERROR,
-                 /* TRANS: Obscure ruleset error */
-                 _("Building %s has unknown req: \"%s\" \"%s\" (%s)"),
-                 b->name, req_type, req_value, filename);
-         req.type = REQ_NONE;
-       }
-
-       ruleset_cache_add(i, eff, range, survives, value, &req, equiv);
-      }
-    }
-
     sz_strlcpy(b->graphic_str,
               secfile_lookup_str_default(file, "-", "%s.graphic", sec[i]));
     sz_strlcpy(b->graphic_alt,
@@ -1369,26 +1242,6 @@
     b->helptext = lookup_helptext(file, sec[i]);
   }
 
-  /*
-   * Hack to allow code that explicitly checks for Palace or City Walls
-   * to work.
-   */
-  game.palace_building = get_building_for_effect(EFT_CAPITAL_CITY);
-  if (game.palace_building == B_LAST) {
-    freelog(LOG_FATAL,
-           /* TRANS: Obscure ruleset error */
-           _("Cannot find any palace building"));
-    exit(EXIT_FAILURE);
-  }
-
-  game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND);
-  if (game.land_defend_building == B_LAST) {
-    freelog(LOG_FATAL,
-           /* TRANS: Obscure ruleset error */
-           _("Cannot find any land defend building"));
-    exit(EXIT_FAILURE);
-  }
-
   /* Some more consistency checking: */
   impr_type_iterate(i) {
     b = &improvement_types[i];
@@ -2409,11 +2262,11 @@
                                     name, j);
       struct requirement req = req_from_str(type, range, survives, value);
 
-      if (req.type == REQ_LAST) {
+      if (req.source.type == REQ_LAST) {
        freelog(LOG_ERROR,
                "Specialist %s has unknown req: \"%s\" \"%s\" \"%s\" %d (%s)",
                name, type, range, value, survives, filename);
-       req.type = REQ_NONE;
+       req.source.type = REQ_NONE;
       }
 
       game.rgame.specialists[i].req[j] = req;
@@ -2490,9 +2343,118 @@
 }
 
 /**************************************************************************
+Load effects requirement list.
+**************************************************************************/
+static void load_req_list(struct section_file *file,
+                         const char *sec, const char *sub,
+                         bool neg, struct effect *peffect)
+{
+  char *type, *name;
+  int j;
+  const char *filename;
+
+  filename = secfile_filename(file);
+
+  for (j = 0;
+      (type = secfile_lookup_str_default(file, NULL, "%s.%s%d.type",
+                                        sec, sub, j));
+      j++) {
+    char *range;
+    bool survives;
+    struct requirement req;
+
+    name = secfile_lookup_str(file, "%s.%s%d.name", sec, sub, j);
+    range = secfile_lookup_str(file, "%s.%s%d.range", sec, sub, j);
+
+    survives = secfile_lookup_bool_default(file, FALSE,
+       "%s.%s%d.survives", sec, sub, j);
+
+    req = req_from_str(type, range, survives, name);
+    if (req.source.type == REQ_LAST) {
+      /* Error.  Log it, clear the req and continue. */
+      freelog(LOG_ERROR,
+         /* TRANS: Obscure ruleset error */
+         _("Section %s has unknown req: \"%s\" \"%s\" (%s)"),
+         sec, type, name, filename);
+      req.source.type = REQ_NONE;
+    } else {
+      struct requirement *preq;
+
+      preq = fc_malloc(sizeof(*preq));
+      *preq = req;
+
+      effect_req_append(peffect, neg, preq);
+    }
+  }
+}
+
+/**************************************************************************
+Load effects.ruleset file
+**************************************************************************/
+static void load_ruleset_effects(struct section_file *file)
+{
+  char **sec, *type;
+  int i, nval;
+  const char *filename;
+
+  filename = secfile_filename(file);
+  (void) check_ruleset_capabilities(file, "+1.0", filename);
+  (void) section_file_lookup(file, "datafile.description");    /* unused */
+
+  /* Parse effects and add them to the effects ruleset cache. */
+  sec = secfile_get_secnames_prefix(file, "effect_", &nval);
+  for (i = 0; i < nval; i++) {
+    enum effect_type eff;
+    int value;
+    struct effect *peffect;
+
+    type = secfile_lookup_str(file, "%s.name", sec[i]);
+
+    if ((eff = effect_type_from_str(type)) == EFT_LAST) {
+      freelog(LOG_ERROR,
+             /* TRANS: Obscure ruleset error */
+             _("Section %s lists unknown effect type: \"%s\" (%s)"),
+             sec[i], type, filename);
+      continue;
+    }
+
+    value = secfile_lookup_int_default(file, 1, "%s.value", sec[i]);
+
+    peffect = effect_new(eff, value);
+
+    load_req_list(file, sec[i], "reqs", FALSE, peffect);
+    load_req_list(file, sec[i], "nreqs", TRUE, peffect);
+  }
+  free(sec);
+
+  section_file_check_unused(file, filename);
+  section_file_free(file);
+
+  /*
+   * Hack to allow code that explicitly checks for Palace or City Walls
+   * to work.
+   */
+  game.palace_building = get_building_for_effect(EFT_CAPITAL_CITY);
+  if (game.palace_building == B_LAST) {
+    freelog(LOG_FATAL,
+           /* TRANS: Obscure ruleset error */
+           _("Cannot find any palace building"));
+    exit(EXIT_FAILURE);
+  }
+
+  game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND);
+  if (game.land_defend_building == B_LAST) {
+    freelog(LOG_FATAL,
+           /* TRANS: Obscure ruleset error */
+           _("Cannot find any land defend building"));
+    exit(EXIT_FAILURE);
+  }
+}
+
+/**************************************************************************
 Load ruleset file
 **************************************************************************/
-static void load_ruleset_game()
+static void load_ruleset_game(void)
 {
   struct section_file file;
   char *sval;
@@ -3061,7 +3023,7 @@
 void load_rulesets(void)
 {
   struct section_file techfile, unitfile, buildfile, govfile, terrfile;
-  struct section_file cityfile, nationfile;
+  struct section_file cityfile, nationfile, effectfile;
 
   freelog(LOG_NORMAL, _("Loading rulesets"));
 
@@ -3086,6 +3048,8 @@
   openload_ruleset_file(&nationfile, "nations");
   load_nation_names(&nationfile);
 
+  openload_ruleset_file(&effectfile, "effects");
+
   load_ruleset_techs(&techfile);
   load_ruleset_cities(&cityfile);
   load_ruleset_governments(&govfile);
@@ -3093,6 +3057,7 @@
   load_ruleset_terrain(&terrfile);    /* terrain must precede nations */
   load_ruleset_buildings(&buildfile);
   load_ruleset_nations(&nationfile);
+  load_ruleset_effects(&effectfile);
   load_ruleset_game();
   translate_data_names();
 }

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