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

[Freeciv-Dev] Re: (PR#2521) effects patch

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: kaufman@xxxxxxxxxxxxxxxxxxxxxx, vasc@xxxxxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#2521) effects patch
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 31 Aug 2004 18:55:06 -0700
Reply-to: rt@xxxxxxxxxxx

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

I updated the effects patch.  It's a bit smaller now.  I didn't really 
edit it at all although I was tempted.  Nor have I tested the new patch.

I had some problems with the AI part.  I fixed it enough to get it to 
compile.  Per, will you search the patch for "#if 0" and for "ocean[1]" 
and see what needs to be changed there?

jason


Index: ai/advdomestic.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.c,v
retrieving revision 1.118
diff -u -r1.118 advdomestic.c
--- ai/advdomestic.c    31 Aug 2004 15:52:46 -0000      1.118
+++ ai/advdomestic.c    1 Sep 2004 01:53:02 -0000
@@ -39,6 +39,7 @@
 
 #include "advdomestic.h"
 
+#if 0 /* FIXME */
 /**************************************************************************
   Calculate desire for land defense. First look for potentially hostile 
   cities on our continent, indicating danger of being attacked by land. 
@@ -915,6 +916,7 @@
 
   return;
 }
+#endif
 
 /***************************************************************************
  * Evaluate the need for units (like caravans) that aid wonder construction.
Index: ai/advdomestic.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdomestic.h,v
retrieving revision 1.6
diff -u -r1.6 advdomestic.h
--- ai/advdomestic.h    21 Jul 2002 00:48:38 -0000      1.6
+++ ai/advdomestic.h    1 Sep 2004 01:53:02 -0000
@@ -21,6 +21,5 @@
 void ai_eval_threat_done(struct player *pplayer);
 void domestic_advisor_choose_build(struct player *pplayer, struct city *pcity,
                                   struct ai_choice *choice);
-void ai_eval_buildings(struct city *pcity);
 
 #endif  /* FC__ADVDOMESTIC_H */
Index: ai/advmilitary.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v
retrieving revision 1.171
diff -u -r1.171 advmilitary.c
--- ai/advmilitary.c    29 Aug 2004 20:14:41 -0000      1.171
+++ ai/advmilitary.c    1 Sep 2004 01:53:02 -0000
@@ -299,8 +299,12 @@
   }
 
   danger = unit_att_rating(punit);
-  if (sailing && city_got_building(pcity, B_COASTAL)) danger /= 2;
-  if (is_air_unit(punit) && city_got_building(pcity, B_SAM)) danger /= 2;
+  if (sailing && get_city_bonus(pcity, EFT_SEA_DEFEND)) {
+    danger /= 2;
+  }
+  if (is_air_unit(punit) && get_city_bonus(pcity, EFT_AIR_DEFEND)) {
+    danger /= 2;
+  }
 
   return danger;
 }
@@ -413,7 +417,7 @@
 static unsigned int assess_danger(struct city *pcity)
 {
   int i;
-  unsigned int danger[5];
+  int danger[5], defender[4];
   struct player *pplayer = city_owner(pcity);
   bool pikemen = FALSE;
   unsigned int urgency = 0;
@@ -523,17 +527,32 @@
     urgency += 10;
   }
 
-  ai_reevaluate_building(pcity, &pcity->ai.building_want[B_CITY],
-                         urgency, danger[1], assess_defense(pcity));
-  ai_reevaluate_building(pcity, &pcity->ai.building_want[B_COASTAL],
-                         urgency, danger[2], 
-                         assess_defense_igwall(pcity));
-  ai_reevaluate_building(pcity, &pcity->ai.building_want[B_SAM],
-                         urgency, danger[3], 
-                         assess_defense_igwall(pcity));
-  ai_reevaluate_building(pcity, &pcity->ai.building_want[B_SDI],
-                         urgency, danger[4], 
-                         assess_defense_igwall(pcity));
+  /* HACK: This needs changing if multiple improvements provide
+   * this effect. */
+  defender[0] = find_source_building(pplayer, EFT_LAND_DEFEND);
+  defender[1] = find_source_building(pplayer, EFT_SEA_DEFEND);
+  defender[2] = find_source_building(pplayer, EFT_AIR_DEFEND);
+  defender[3] = find_source_building(pplayer, EFT_MISSILE_DEFEND);
+
+  if (defender[0] != B_LAST) {
+    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[0]],
+       urgency, danger[1], assess_defense(pcity));
+  }
+  if (defender[1] != B_LAST) {
+    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[1]],
+       urgency, danger[2], 
+       assess_defense_igwall(pcity));
+  }
+  if (defender[2] != B_LAST) {
+    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[2]],
+       urgency, danger[3], 
+       assess_defense_igwall(pcity));
+  }
+  if (defender[3] != B_LAST) {
+    ai_reevaluate_building(pcity, &pcity->ai.building_want[defender[3]],
+       urgency, danger[4], 
+       assess_defense_igwall(pcity));
+  }
 
   pcity->ai.danger = danger[0];
   pcity->ai.urgency = urgency;
@@ -775,9 +794,9 @@
             !can_build_unit_direct(pcity, unit_types[unit_type].obsoleted_by))
         && unit_types[unit_type].attack_strength > 0 /* or we'll get SIGFPE */
         && move_type == orig_move_type) {
-      /* TODO: Case for B_AIRPORT. -- Raahul */
+      /* TODO: Case for Airport. -- Raahul */
       int will_be_veteran = (move_type == LAND_MOVING
-                             || player_knows_improvement_tech(pplayer, 
B_PORT));
+         || find_source_building(pplayer, EFT_SEA_VETERAN) != B_LAST);
       /* Cost (shield equivalent) of gaining these techs. */
       /* FIXME? Katvrr advises that this should be weighted more heavily in big
        * danger. */
@@ -1124,6 +1143,7 @@
 {
   enum unit_move_type move_type;
   struct player *pplayer = city_owner(pcity);
+  Impr_Type_id id;
 
   /* Sanity */
   if (!is_unit_choice_type(choice->choice)) return;
@@ -1131,36 +1151,25 @@
   if (do_make_unit_veteran(pcity, choice->choice)) return;
 
   move_type = get_unit_type(choice->choice)->move_type;
-  if (improvement_variant(B_BARRACKS)==1) {
-    /* Barracks will work for all units! */
-    move_type = LAND_MOVING;
-  }
-
   switch(move_type) {
   case LAND_MOVING:
-    if (player_knows_improvement_tech(pplayer, B_BARRACKS3)) {
-      choice->choice = B_BARRACKS3;
-      choice->type = CT_BUILDING;
-    } else if (player_knows_improvement_tech(pplayer, B_BARRACKS2)) {
-      choice->choice = B_BARRACKS2;
-      choice->type = CT_BUILDING;
-    } else if (player_knows_improvement_tech(pplayer, B_BARRACKS)) {
-      choice->choice = B_BARRACKS;
+    if ((id = find_source_building(pplayer, EFT_LAND_VETERAN)) != B_LAST) {
+      choice->choice = id;
       choice->type = CT_BUILDING;
     }
     break;
   case SEA_MOVING:
-    if (player_knows_improvement_tech(pplayer, B_PORT)) {
-      choice->choice = B_PORT;
+    if ((id = find_source_building(pplayer, EFT_SEA_VETERAN)) != B_LAST) {
+      choice->choice = id;
       choice->type = CT_BUILDING;
     }
     break;
   case HELI_MOVING:
   case AIR_MOVING:
-    if (player_knows_improvement_tech(pplayer, B_AIRPORT)
-        && pcity->shield_surplus > impr_build_shield_cost(B_AIRPORT) / 10) {
+    if ((id = find_source_building(pplayer, EFT_AIR_VETERAN)) != B_LAST
+        && pcity->shield_surplus > impr_build_shield_cost(id) / 10) {
       /* Only build this if we have really high production */
-      choice->choice = B_AIRPORT;
+      choice->choice = id;
       choice->type = CT_BUILDING;
     }
     break;
@@ -1199,6 +1208,7 @@
   /* Otherwise no need to defend yet */
   if (pcity->ai.danger != 0) { 
     int num_defenders = unit_list_size(&ptile->units);
+    int land_id, sea_id, air_id;
 
     /* First determine the danger.  It is measured in percents of our 
      * defensive strength, capped at 200 + urgency */
@@ -1224,40 +1234,50 @@
      * 2. (80 - pcity->shield_stock) * 2 below is hardcoded price of walls */
     /* We will build walls if we can and want and (have "enough" defenders or
      * can just buy the walls straight away) */
-    if (pcity->ai.building_want[B_CITY] != 0 && our_def != 0 
-        && can_build_improvement(pcity, B_CITY)
+
+    /* HACK: This needs changing if multiple improvements provide
+     * this effect. */
+    land_id = find_source_building(pplayer, EFT_LAND_DEFEND);
+    sea_id = find_source_building(pplayer, EFT_SEA_DEFEND);
+    air_id = find_source_building(pplayer, EFT_AIR_DEFEND);
+
+    if (land_id != B_LAST
+       && pcity->ai.building_want[land_id] != 0 && our_def != 0 
+        && can_build_improvement(pcity, land_id)
         && (danger < 101 || num_defenders > 1
             || (pcity->ai.grave_danger == 0 
                 && pplayer->economic.gold > (80 - pcity->shield_stock) * 2)) 
         && ai_fuzzy(pplayer, TRUE)) {
       /* NB: great wall is under domestic */
-      choice->choice = B_CITY;
+      choice->choice = land_id;
       /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_CITY];
+      choice->want = pcity->ai.building_want[land_id];
       if (urgency == 0 && choice->want > 100) {
         choice->want = 100;
       }
       choice->type = CT_BUILDING;
 
-    } else if (pcity->ai.building_want[B_COASTAL] != 0 && our_def != 0 
-               && can_build_improvement(pcity, B_COASTAL) 
+    } else if (sea_id != B_LAST
+              && pcity->ai.building_want[sea_id] != 0 && our_def != 0 
+               && can_build_improvement(pcity, sea_id) 
                && (danger < 101 || num_defenders > 1) 
                && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = B_COASTAL;
+      choice->choice = sea_id;
       /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_COASTAL];
+      choice->want = pcity->ai.building_want[sea_id];
       if (urgency == 0 && choice->want > 100) {
         choice->want = 100;
       }
       choice->type = CT_BUILDING;
 
-    } else if (pcity->ai.building_want[B_SAM] != 0 && our_def != 0 
-               && can_build_improvement(pcity, B_SAM) 
+    } else if (air_id != B_LAST
+              && pcity->ai.building_want[air_id] != 0 && our_def != 0 
+               && can_build_improvement(pcity, air_id) 
                && (danger < 101 || num_defenders > 1) 
                && ai_fuzzy(pplayer, TRUE)) {
-      choice->choice = B_SAM;
+      choice->choice = air_id;
       /* building_want is hacked by assess_danger */
-      choice->want = pcity->ai.building_want[B_SAM];
+      choice->want = pcity->ai.building_want[air_id];
       if (urgency == 0 && choice->want > 100) {
         choice->want = 100;
       }
@@ -1267,7 +1287,7 @@
       /* Consider building defensive units units */
       process_defender_want(pplayer, pcity, danger, choice);
       if (urgency == 0 && unit_types[choice->choice].defense_strength == 1) {
-        if (city_got_barracks(pcity)) {
+        if (get_city_bonus(pcity, EFT_LAND_REGEN)) {
           /* unlikely */
           choice->want = MIN(49, danger);
         } else {
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.160
diff -u -r1.160 aicity.c
--- ai/aicity.c 13 Aug 2004 15:59:11 -0000      1.160
+++ ai/aicity.c 1 Sep 2004 01:53:02 -0000
@@ -20,6 +20,7 @@
 
 #include "city.h"
 #include "combat.h"
+#include "effects.h"
 #include "events.h"
 #include "fcintl.h"
 #include "game.h"
@@ -28,6 +29,7 @@
 #include "map.h"
 #include "packets.h"
 #include "player.h"
+#include "rand.h"
 #include "shared.h"
 #include "support.h"
 #include "unit.h"
@@ -59,114 +61,363 @@
 static void resolve_city_emergency(struct player *pplayer, struct city *pcity);
 static void ai_sell_obsolete_buildings(struct city *pcity);
 
-/**************************************************************************
-  This calculates the usefulness of pcity to us. Note that you can pass
-  another player's ai_data structure here for evaluation by different
-  priorities.
-**************************************************************************/
-int ai_eval_calc_city(struct city *pcity, struct ai_data *ai)
-{
-  int i = (pcity->food_surplus * ai->food_priority
-           + pcity->shield_surplus * ai->shield_priority
-           + pcity->luxury_total * ai->luxury_priority
-           + pcity->tax_total * ai->gold_priority
-           + pcity->science_total * ai->science_priority
-           + pcity->ppl_happy[4] * ai->happy_priority
-           - pcity->ppl_unhappy[4] * ai->unhappy_priority
-           - pcity->ppl_angry[4] * ai->angry_priority
-           - pcity->pollution * ai->pollution_priority);
-  
-  if (pcity->food_surplus < 0 || pcity->shield_surplus < 0) {
-    /* The city is unmaintainable, it can't be good */
-    i = MIN(i, 0);
+/************************************************************************** 
+  Calculate effects. A few base variables:
+    c - number of cities we have in current range
+    u - units we have of currently affected type
+    v - the want for the improvement we are considering
+
+  This function contains a whole lot of WAGs. We ignore cond_* for now,
+  thinking that one day we may fulfill the cond_s anyway. In general, we
+  first add bonus for city improvements, then for wonders.
+
+  TODO: Calculate per-continent aggregates of various data, and use this
+  for wonders below for better wonder placements.
+**************************************************************************/
+static void adjust_building_want_by_effects(struct city *pcity, int id)
+{
+  struct player *pplayer = city_owner(pcity);
+  struct impr_type *pimpr = get_improvement_type(id);
+  int v = 0;
+  int cities[EFR_LAST];
+  int nplayers = game.nplayers
+                 - team_count_members_alive(pplayer->team);
+  struct ai_data *ai = ai_data_get(pplayer);
+  struct tile *ptile = map_get_tile(pcity->x, pcity->y);
+  bool capital = is_capital(pcity);
+  struct government *gov = get_gov_pplayer(pplayer);
+
+  if (building_has_effect(id, EFT_CAPITAL_CITY)) {
+    pcity->ai.building_want[id] = 0;
+    return;
   }
 
-  return i;
+  /* Find number of cities per range.  */
+  cities[EFR_PLAYER] = city_list_size(&pplayer->cities);
+  cities[EFR_WORLD] = cities[EFR_PLAYER]; /* kludge. */
+
+  cities[EFR_CONTINENT] = 0;
+  city_list_iterate(pplayer->cities, acity) {
+    if (map_get_tile(acity->x, acity->y)->continent == ptile->continent)
+      cities[EFR_CONTINENT]++;
+  } city_list_iterate_end;
+
+  cities[EFR_CITY] = 1;
+  cities[EFR_LOCAL] = 0;
+
+  /* Calculate desire value. */
+  eft_vector_iterate(get_building_effect_types(id), ptype) {
+    eff_list_iterate(*get_building_effects(id, *ptype), peff) {
+
+      if (eff_eventually_active(TARGET_BUILDING, pplayer, pcity, id,
+                               NULL, id, peff)) {
+       int amount = peff->value, c = cities[peff->range];
+
+       switch (*ptype) {
+         /* Modify general city parameter effects. We do them fast and furious
+          * for now, since we will do this more accurately later on with a 
+          * different kind of code. */
+         case EFT_INCITE_DIST_ADJ:
+         case EFT_INCITE_DIST_PCT:
+         case EFT_UPKEEP_FREE:
+         case EFT_MAKE_CONTENT_MIL_PER:
+         case EFT_FOOD_PER_TILE:
+         case EFT_FOOD_ADD_TILE:
+         case EFT_MAKE_HAPPY:
+         case EFT_POLLU_POP_PCT:
+         case EFT_POLLU_PROD_PCT:
+         case EFT_TRADE_PER_TILE:
+         case EFT_PROD_ADD_TILE:
+         case EFT_PROD_TO_GOLD:
+         case EFT_TRADE_INC_TILE:
+         case EFT_NO_UNHAPPY:
+         case EFT_LUXURY_BONUS:
+         case EFT_UNIT_RECOVER:
+         case EFT_CAPITAL_CITY:
+         case EFT_FOOD_BONUS:
+         case EFT_FOOD_PCT:
+         case EFT_FOOD_INC_TILE:
+         case EFT_FORCE_CONTENT_PCT:
+         case EFT_LUXURY_PCT:
+         case EFT_MAKE_CONTENT_PCT:
+         case EFT_POLLU_ADJ:
+         case EFT_POLLU_PCT:
+         case EFT_POLLU_POP_ADJ:
+         case EFT_POLLU_PROD_ADJ:
+         case EFT_PROD_PCT:
+         case EFT_PROD_INC_TILE:
+         case EFT_PROD_PER_TILE:
+         case EFT_SCIENCE_PCT:
+         case EFT_SPACE_PART:
+         case EFT_TAX_PCT:
+         case EFT_TRADE_ADD_TILE:
+         case EFT_TRADE_BONUS:
+         case EFT_TRADE_PCT:
+         case EFT_UPGRADE_ONE_STEP:
+         case EFT_UPGRADE_ALL_STEP:
+         case EFT_SEA_VET_COMBAT:
+         case EFT_AIR_VET_COMBAT:
+         case EFT_NO_UPKEEP:
+           /* FIXME */
+           break;
+         case EFT_FORCE_CONTENT:
+           if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
+             v += pcity->ppl_unhappy[0] * 5;
+             v += 5 * c;
+           }
+           break;
+         case EFT_MAKE_CONTENT:
+           if (!government_has_flag(gov, G_NO_UNHAPPY_CITIZENS)) {
+             v += pcity->ppl_unhappy[0] * amount;
+             v += amount * 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_PROD_BONUS:
+           v += (100 + amount) * pcity->shield_prod * ai->shield_priority / 
200;
+           v += (100 + amount) * c * ai->shield_priority / 400;
+           break;
+         case EFT_SCIENCE_BONUS:
+           if (!ai_wants_no_science(pplayer)) {
+             v += (100 + amount) * pcity->science_total * ai->science_priority 
/ 200;
+             v += (100 + amount) * c * ai->science_priority / 400;
+           }
+           break;
+         case EFT_TAX_BONUS:
+           if (!ai_wants_no_science(pplayer)) {
+             /* Increase gold income so that we can lower taxes and research 
more */
+             v += (pplayer->economic.tax * 2 + amount) * pcity->tax_total 
+               * ai->gold_priority / 200;
+             v += (pplayer->economic.tax * 2 + amount) * c * ai->gold_priority 
/ 400;
+           } else {
+             v += (100 + amount) * pcity->tax_total * ai->gold_priority / 400;
+             v += (100 + amount) * c * ai->gold_priority / 800;
+           }
+           break;
+         case EFT_CORRUPT_PCT:
+           v += (pcity->corruption / 2) 
+             * MAX(ai->science_priority, ai->gold_priority);
+           v += c * MAX(ai->science_priority, ai->gold_priority) / 10;
+           break;
+         case EFT_WASTE_PCT:
+           v += (pcity->shield_waste / 2) * ai->shield_priority;
+           v += c * ai->shield_priority / 10;
+           break;
+
+           /* Special cased effects */
+         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 + 25;
+           break;
+         case EFT_AIRLIFT:
+           v += c + ai->stats.units[UCL_LAND];
+           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 += 50;
+           }
+           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->food_surplus * ai->food_priority * amount / 10;
+           }
+           v += c * amount / game.aqueduct_size;
+           break;
+         case EFT_SS_STRUCTURAL:
+         case EFT_SS_COMPONENT:
+         case EFT_SS_MODULE:
+           if (game.spacerace && ai->diplomacy.strategy == WIN_SPACE) {
+             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_ONE_LEAP:
+           v += 5 * c + ai->stats.units[UCL_LAST] * 2;
+           break;
+         case EFT_UPGRADE_ALL_LEAP:
+           v += 5 * c + ai->stats.units[UCL_LAST] * 4;
+           break;
+         case EFT_SEA_DEFEND:
+           if (ai_handicap(pplayer, H_DEFENSIVE)) {
+             v += amount * 10; /* make AI slow */
+           }
+           /* FIXME: use of ocean[1] here is wrong.  We need to calculate
+            * the right ocean(s) for this city, and figure out how to
+            * handle the multiple-city case. */
+           v += ai->threats.ocean[1] ? 8 * amount : amount;  /* for single 
city */
+           v += (amount + ai->threats.ocean[1] - 1) * c; /* for wonder */
+           if (capital) {
+             v += amount * 10; /* 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 * 5 + amount * c : c;
+           break;
+         case EFT_MISSILE_DEFEND:
+           if (ai->threats.missile
+               && (ai->threats.continent[ptile->continent] || capital)) {
+             v += amount * 5 + (amount - 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->x, pcity->y))) {
+             v += !ai->threats.igwall ? 15 + (capital * amount * 5) : 10;
+           }
+           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_LAST:
+           freelog(LOG_ERROR, "Bad effect type.");
+           break;
+       }
+      }
+
+    } eff_list_iterate_end;
+  } eft_vector_iterate_end;
+
+  /* Reduce want if building gets obsoleted soon */
+  if (tech_exists(pimpr->obsolete_by)) {
+    v -= v / MAX(1, num_unknown_techs_for_goal(pplayer, pimpr->obsolete_by));
+   }
+
+  /* Adjust by building cost */
+  v -= pimpr->build_cost / (pcity->shield_surplus * 10 + 1);
+
+  /* Set */
+  pcity->ai.building_want[id] = v;
 }
-     
+
 /************************************************************************** 
-...
+  Prime pcity->ai.building_want[]
 **************************************************************************/
 static void ai_manage_buildings(struct player *pplayer)
-{ /* we have just managed all our cities but not chosen build for them yet */
-  struct government *g = get_gov_pplayer(pplayer);
-  Tech_Type_id j;
-  int values[B_LAST], leon = 0;
-  bool palace = FALSE;
-  int corr = 0;
-  memset(values, 0, sizeof(values));
-  memset(pplayer->ai.tech_want, 0, sizeof(pplayer->ai.tech_want));
-
-  if (find_palace(pplayer) || g->corruption_level == 0) palace = TRUE;
-  city_list_iterate(pplayer->cities, pcity)
-    ai_eval_buildings(pcity);
-    if (!palace) corr += pcity->corruption * 8;
-    impr_type_iterate(i) {
-      if (pcity->ai.building_want[i] > 0) values[i] += 
pcity->ai.building_want[i];
-    } impr_type_iterate_end;
-
-    if (pcity->ai.building_want[B_LEONARDO] > leon)
-      leon = pcity->ai.building_want[B_LEONARDO];
-  city_list_iterate_end;
-
-/* this is a weird place to iterate a units list! */
-  unit_list_iterate(pplayer->units, punit)
-    if (is_sailing_unit(punit))
-      values[B_MAGELLAN] +=
-         unit_build_shield_cost(punit->type) * 2 * SINGLE_MOVE /
-         unit_type(punit)->move_rate;
-  unit_list_iterate_end;
-  values[B_MAGELLAN] *= 100 * SHIELD_WEIGHTING;
-  values[B_MAGELLAN] /= (MORT * impr_build_shield_cost(B_MAGELLAN));
-
-  /* This is a weird place to put tech advice */
-  /* This was: > G_DESPOTISM; should maybe remove test, depending
-   * on new government evaluation etc, but used for now for
-   * regression testing --dwp */
-  if (g->index != game.default_government
-      && g->index != game.government_when_anarchy) {
-    impr_type_iterate(i) {
-      j = improvement_types[i].tech_req;
-      if (get_invention(pplayer, j) != TECH_KNOWN)
-        pplayer->ai.tech_want[j] += values[i];
-      /* if it is a bonus tech double it's value since it give a free
-        tech */
-      if (game.global_advances[j] == 0 && tech_flag(j, TF_BONUS_TECH))
-       pplayer->ai.tech_want[j] *= 2;
-      /* this probably isn't right -- Syela */
-      /* since it assumes that the next tech is as valuable as the
-        current -- JJCogliati */
-    } impr_type_iterate_end;
-  } /* tired of researching pottery when we need to learn Republic!! -- Syela 
*/
-
-
-  city_list_iterate(pplayer->cities, pcity)
-    pcity->ai.building_want[B_MAGELLAN] = values[B_MAGELLAN];
-    pcity->ai.building_want[B_ASMITHS] = values[B_ASMITHS];
-    pcity->ai.building_want[B_CURE] = values[B_CURE];
-    pcity->ai.building_want[B_HANGING] += values[B_CURE];
-    pcity->ai.building_want[B_WALL] = values[B_WALL];
-    pcity->ai.building_want[B_HOOVER] = values[B_HOOVER];
-    pcity->ai.building_want[B_BACH] = values[B_BACH];
-/* yes, I know that HOOVER and BACH should be continent-only not global */
-    pcity->ai.building_want[B_MICHELANGELO] = values[B_MICHELANGELO];
-    pcity->ai.building_want[B_ORACLE] = values[B_ORACLE];
-    pcity->ai.building_want[B_PYRAMIDS] = values[B_PYRAMIDS];
-    pcity->ai.building_want[B_SETI] = values[B_SETI];
-    pcity->ai.building_want[B_SUNTZU] = values[B_SUNTZU];
-    pcity->ai.building_want[B_WOMENS] = values[B_WOMENS];
-    pcity->ai.building_want[B_LEONARDO] = leon; /* hopefully will fix */
-    pcity->ai.building_want[B_PALACE] = corr; /* urgent enough? */
-  city_list_iterate_end;
-
-  city_list_iterate(pplayer->cities, pcity) /* wonder-kluge */
-    impr_type_iterate(i) {
-      if (!pcity->is_building_unit && is_wonder(i) &&
-          is_wonder(pcity->currently_building))
-       /* this should encourage completion of wonders, I hope! -- Syela */
-        pcity->ai.building_want[i] += pcity->shield_stock / 2;
-    } impr_type_iterate_end;
-  city_list_iterate_end;
+/* TODO:  RECALC_SPEED should be configurable to ai difficulty. -kauf  */
+#define RECALC_SPEED 5
+{
+  impr_type_iterate(id) {
+    if (!can_player_build_improvement(pplayer, id)
+        || improvement_obsolete(pplayer, id)) {
+      continue;
+    }
+    city_list_iterate(pplayer->cities, pcity) {
+      if (pcity->ai.next_recalc > game.turn) {
+        continue; /* do not recalc yet */
+      } else {
+        pcity->ai.building_want[id] = 0; /* do recalc */
+      }
+      if (city_got_building(pcity, id)
+          || pcity->shield_surplus == 0
+          || !can_build_improvement(pcity, id)
+          || improvement_redundant(pplayer, pcity, id, FALSE)) {
+        continue; /* Don't build redundant buildings */
+      }
+      adjust_building_want_by_effects(pcity, id);
+      CITY_LOG(LOG_DEBUG, pcity, "want to build %s with %d", 
+               get_improvement_name(id), pcity->ai.building_want[id]);
+    } city_list_iterate_end;
+  } impr_type_iterate_end;
+
+  /* Reset recalc counter */
+  city_list_iterate(pplayer->cities, pcity) {
+    if (pcity->ai.next_recalc <= game.turn) {
+      /* This will spread recalcs out so that no one turn end is 
+       * much longer than others */
+      pcity->ai.next_recalc = game.turn + myrand(RECALC_SPEED) + RECALC_SPEED;
+    }
+  } city_list_iterate_end;
 }
 
 /*************************************************************************** 
@@ -296,8 +547,8 @@
     if (best_role_unit(pcity, F_TRADE_ROUTE) != U_LAST) {
       pcity->ai.choice.choice = best_role_unit(pcity, F_TRADE_ROUTE);
       pcity->ai.choice.type = CT_NONMIL;
-    } else if (can_build_improvement(pcity, B_CAPITAL)) {
-      pcity->ai.choice.choice = B_CAPITAL;
+    } else if (can_build_improvement(pcity, game.default_building)) {
+      pcity->ai.choice.choice = game.default_building;
       pcity->ai.choice.type = CT_BUILDING;
     } else if (best_role_unit(pcity, F_SETTLERS) != U_LAST) {
       pcity->ai.choice.choice = best_role_unit(pcity, F_SETTLERS);
@@ -355,7 +606,8 @@
 static void try_to_sell_stuff(struct player *pplayer, struct city *pcity)
 {
   impr_type_iterate(id) {
-    if (can_sell_building(pcity, id) && id != B_CITY) {
+    if (can_sell_building(pcity, id)
+       && !building_has_effect(id, EFT_LAND_DEFEND)) {
 /* selling walls to buy defenders is counterproductive -- Syela */
       really_handle_city_sell(pplayer, pcity, id);
       break;
@@ -488,7 +740,7 @@
 
     if (bestchoice.type != CT_BUILDING
         && unit_type_flag(bestchoice.choice, F_CITIES)) {
-      if (!city_got_effect(pcity, B_GRANARY) 
+      if (!get_city_bonus(pcity, EFT_GROWTH_FOOD)
           && pcity->size == 1
           && city_granary_size(pcity->size)
              > pcity->food_stock + pcity->food_surplus) {
@@ -633,7 +885,7 @@
 static bool building_unwanted(struct player *plr, Impr_Type_id i)
 {
   return (ai_wants_no_science(plr)
-         && (i == B_LIBRARY || i == B_UNIVERSITY || i == B_RESEARCH));
+          && building_has_effect(i, EFT_SCIENCE_BONUS));
 }
 
 /**************************************************************************
@@ -645,8 +897,10 @@
 
   built_impr_iterate(pcity, i) {
     if(!is_wonder(i) 
-       && i != B_CITY /* selling city walls is really, really dumb -- Syela */
-       && (wonder_replacement(pcity, i) || 
building_unwanted(city_owner(pcity), i))) {
+       && !building_has_effect(i, EFT_LAND_DEFEND)
+             /* selling city walls is really, really dumb -- Syela */
+       && (building_replaced(pcity, i)
+        || building_unwanted(city_owner(pcity), i))) {
       do_sell_building(pplayer, pcity, i);
       notify_player_ex(pplayer, pcity->x, pcity->y, E_IMP_SOLD,
                       _("Game: %s is selling %s (not needed) for %d."), 
Index: ai/aicity.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.h,v
retrieving revision 1.22
diff -u -r1.22 aicity.h
--- ai/aicity.h 24 May 2004 02:09:27 -0000      1.22
+++ ai/aicity.h 1 Sep 2004 01:53:03 -0000
@@ -14,19 +14,39 @@
 #define FC__AICITY_H
 
 #include "unit.h"              /* enum unit_move_type */
+#include "city.h"
+#include "aidata.h"
 
 struct player;
-struct city;
 struct ai_choice;
-struct ai_data;
-
-int ai_eval_calc_city(struct city *pcity, struct ai_data *ai);
 
 void ai_manage_cities(struct player *pplayer);
 
 Unit_Type_id ai_choose_defender_versus(struct city *pcity, Unit_Type_id v);
 
-enum ai_city_task { AICITY_NONE, AICITY_TECH, AICITY_TAX, AICITY_PROD};
-/* These are not used (well, except AICITY_NONE)  --dwp */
+/**************************************************************************
+  This calculates the usefulness of pcity to us. Note that you can pass
+  another player's ai_data structure here for evaluation by different
+  priorities.
+**************************************************************************/
+static inline int ai_eval_calc_city(struct city *pcity, struct ai_data *ai)
+{
+  int i = (pcity->food_surplus * ai->food_priority
+           + pcity->shield_surplus * ai->shield_priority
+           + pcity->luxury_total * ai->luxury_priority
+           + pcity->tax_total * ai->gold_priority
+           + pcity->science_total * ai->science_priority
+           + pcity->ppl_happy[4] * ai->happy_priority
+           - pcity->ppl_unhappy[4] * ai->unhappy_priority
+           - pcity->ppl_angry[4] * ai->angry_priority
+           - pcity->pollution * ai->pollution_priority);
+
+  if (pcity->food_surplus < 0 || pcity->shield_surplus < 0) {
+    /* The city is unmaintainable, it can't be good */
+    i = MIN(i, 0);
+  }
+
+  return i;
+}
 
 #endif  /* FC__AICITY_H */
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.36
diff -u -r1.36 aidata.c
--- ai/aidata.c 30 Aug 2004 21:20:33 -0000      1.36
+++ ai/aidata.c 1 Sep 2004 01:53:03 -0000
@@ -17,6 +17,7 @@
 
 #include "aisupport.h"
 #include "city.h"
+#include "effects.h"
 #include "game.h"
 #include "government.h"
 #include "log.h"
@@ -59,6 +60,16 @@
   struct ai_data *ai = &aidata[pplayer->player_no];
   int i, nuke_units = num_role_units(F_NUCLEAR);
   bool danger_of_nukes = FALSE;
+#if 0 /* FIXME */
+  bool can_build_antisea =
+    (find_source_building(pplayer, EFT_SEA_DEFEND) != B_LAST);
+  bool can_build_antiair =
+    (find_source_building(pplayer, EFT_AIR_DEFEND) != B_LAST);
+  bool can_build_antimissile =
+    (find_source_building(pplayer, EFT_MISSILE_DEFEND) != B_LAST);
+  bool can_build_antinuke =
+    (find_source_building(pplayer, EFT_NUKE_PROOF) != B_LAST);
+#endif
   int ally_strength = -1;
   struct player *ally_strongest = NULL;
 
@@ -71,6 +82,7 @@
   ai->threats.air       = FALSE;
   ai->threats.nuclear   = 0; /* none */
   ai->threats.ocean     = fc_calloc(ai->num_oceans + 1, sizeof(bool));
+  ai->threats.igwall    = FALSE;
 
   players_iterate(aplayer) {
     if (!is_player_dangerous(pplayer, aplayer)) {
@@ -87,6 +99,10 @@
     } city_list_iterate_end;
 
     unit_list_iterate(aplayer->units, punit) {
+      if (unit_flag(punit, F_IGWALL)) {
+        ai->threats.igwall = TRUE;
+      }
+
       if (is_sailing_unit(punit)) {
         /* If the enemy has not started sailing yet, or we have total
          * control over the seas, don't worry, keep attacking. */
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.15
diff -u -r1.15 aidata.h
--- ai/aidata.h 29 Aug 2004 19:43:37 -0000      1.15
+++ ai/aidata.h 1 Sep 2004 01:53:03 -0000
@@ -76,6 +76,7 @@
     bool air;         /* check for non-allied offensive aircraft */
     bool missile;     /* check for non-allied missiles */
     int nuclear;      /* nuke check: 0=no, 1=capability, 2=built */
+    bool igwall;      /* enemies have igwall units */
   } threats;
 
   /* Keeps track of which continents are fully explored already */
@@ -89,6 +90,8 @@
   /* This struct is used for statistical unit building, eg to ensure
    * that we don't build too few or too many units of a given type. */
   struct {
+    int triremes;
+    int units[UCL_LAST + 1]; /* no. units by class */
     int *workers;     /* cities to workers on continent*/
     int *cities;      /* number of cities on continent */
     int passengers;   /* number of passengers waiting for boats */
Index: ai/aidiplomat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidiplomat.c,v
retrieving revision 1.38
diff -u -r1.38 aidiplomat.c
--- ai/aidiplomat.c     29 Aug 2004 17:54:13 -0000      1.38
+++ ai/aidiplomat.c     1 Sep 2004 01:53:03 -0000
@@ -173,11 +173,8 @@
     }
     incite_cost = city_incite_cost(pplayer, acity);
     if (HOSTILE_PLAYER(pplayer, ai, city_owner(acity))
-        && !city_got_building(acity, B_PALACE)
-        && !government_has_flag(get_gov_pplayer(city_owner(acity)),
-                                G_UNBRIBABLE)
-        && (incite_cost <
-            pplayer->economic.gold - pplayer->ai.est_upkeep)) {
+        && (incite_cost < INCITE_IMPOSSIBLE_COST)
+        && (incite_cost < pplayer->economic.gold - pplayer->ai.est_upkeep)) {
       /* incite gain (FIXME: we should count wonders too but need to
          cache that somehow to avoid CPU hog -- Per) */
       gain_incite = acity->food_prod * FOOD_WEIGHTING
@@ -345,11 +342,9 @@
       continue; 
     }
 
-    can_incite = !(city_got_building(acity, B_PALACE)
-                   || government_has_flag(get_gov_pplayer(aplayer), 
-                                          G_UNBRIBABLE));
-
     incite_cost = city_incite_cost(pplayer, acity);
+    can_incite = (incite_cost < INCITE_IMPOSSIBLE_COST);
+
     dipldef = (count_diplomats_on_tile(acity->x, acity->y) > 0);
     /* Three actions to consider:
      * 1. establishing embassy OR
Index: ai/aiexplorer.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiexplorer.c,v
retrieving revision 1.3
diff -u -r1.3 aiexplorer.c
--- ai/aiexplorer.c     26 Aug 2004 22:22:03 -0000      1.3
+++ ai/aiexplorer.c     1 Sep 2004 01:53:03 -0000
@@ -110,7 +110,7 @@
    */
   if ((likely_ocean(x, y, pplayer) < 50) || 
       is_likely_coastline(x, y, pplayer) ||
-      (player_owns_active_wonder(pplayer, B_LIGHTHOUSE))) {
+      (get_player_bonus(pplayer, EFT_NO_SINK_DEEP))) {
     return FALSE;
   } else {
     return TRUE;
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.121
diff -u -r1.121 aitools.c
--- ai/aitools.c        31 Aug 2004 15:35:31 -0000      1.121
+++ ai/aitools.c        1 Sep 2004 01:53:03 -0000
@@ -792,8 +792,6 @@
                                     struct government *g)
 {
   int free_happy;
-  bool have_police;
-  int variant;
   int unhap = 0;
 
   /* bail out now if happy_cost is 0 */
@@ -802,14 +800,10 @@
   }
   
   free_happy  = citygov_free_happy(pcity, g);
-  have_police = city_got_effect(pcity, B_POLICE);
-  variant = improvement_variant(B_WOMENS);
 
-  if (variant == 0 && have_police) {
-    /* ??  This does the right thing for normal Republic and Democ -- dwp */
-    free_happy += g->unit_happy_cost_factor;
-  }
-  
+  /* ??  This does the right thing for normal Republic and Democ -- dwp */
+  free_happy += get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL);
+
   unit_list_iterate(pcity->units_supported, punit) {
     int happy_cost = utype_happy_cost(unit_type(punit), g);
 
@@ -829,7 +823,7 @@
       continue;
     }
 
-    if (variant == 1 && have_police) {
+    if (get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL_PER)) {
       happy_cost--;
     }
     adjust_city_free_cost(&free_happy, &happy_cost);
Index: ai/aiunit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v
retrieving revision 1.332
diff -u -r1.332 aiunit.c
--- ai/aiunit.c 31 Aug 2004 18:21:09 -0000      1.332
+++ ai/aiunit.c 1 Sep 2004 01:53:04 -0000
@@ -1720,14 +1720,12 @@
       city_list_iterate(aplayer->cities, pcity) {
         if (ground) {
           cur = WARMAP_COST(pcity->x, pcity->y);
-          if (city_got_building(pcity, B_BARRACKS)
-              || city_got_building(pcity, B_BARRACKS2)
-              || city_got_building(pcity, B_BARRACKS3)) {
+          if (get_city_bonus(pcity, EFT_LAND_REGEN)) {
             cur /= 3;
           }
         } else {
           cur = WARMAP_SEACOST(pcity->x, pcity->y);
-          if (city_got_building(pcity, B_PORT)) {
+          if (get_city_bonus(pcity, EFT_SEA_REGEN)) {
             cur /= 3;
           }
         }
Index: client/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.43
diff -u -r1.43 citydlg_common.c
--- client/citydlg_common.c     28 Aug 2004 19:15:39 -0000      1.43
+++ client/citydlg_common.c     1 Sep 2004 01:53:04 -0000
@@ -281,7 +281,7 @@
                                     int id, bool is_unit,
                                     struct city *pcity)
 {
-  if (!is_unit && id == B_CAPITAL) {
+  if (!is_unit && building_has_effect(id, EFT_PROD_TO_GOLD)) {
     my_snprintf(buffer, buffer_len, _("%s (XX) %d/turn"),
                get_impr_name_ex(pcity, id), MAX(0, pcity->shield_surplus));
   } else {
@@ -333,7 +333,7 @@
     my_snprintf(buf[2], column_size, "%d", unit_build_shield_cost(id));
   } else {
     /* Total & turns left meaningless on capitalization */
-    if (id == B_CAPITAL) {
+    if (building_has_effect(id, EFT_PROD_TO_GOLD)) {
       my_snprintf(buf[0], column_size, get_improvement_type(id)->name);
       buf[1][0] = '\0';
       my_snprintf(buf[2], column_size, "---");
@@ -341,7 +341,7 @@
       my_snprintf(buf[0], column_size, get_improvement_type(id)->name);
 
       /* from city.c get_impr_name_ex() */
-      if (pcity && wonder_replacement(pcity, id)) {
+      if (pcity && building_replaced(pcity, id)) {
        my_snprintf(buf[1], column_size, "*");
       } else {
        const char *state = "";
@@ -365,7 +365,7 @@
 
   /* Add the turns-to-build entry in the 4th position */
   if (pcity) {
-    if (!is_unit && id == B_CAPITAL) {
+    if (!is_unit && building_has_effect(id, EFT_PROD_TO_GOLD)) {
       my_snprintf(buf[3], column_size, _("%d/turn"),
                  MAX(0, pcity->shield_surplus));
     } else {
Index: client/climisc.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/climisc.c,v
retrieving revision 1.136
diff -u -r1.136 climisc.c
--- client/climisc.c    28 Aug 2004 19:15:39 -0000      1.136
+++ client/climisc.c    1 Sep 2004 01:53:04 -0000
@@ -559,7 +559,7 @@
  struct items and also sort it.
 
  section 0: normal buildings
- section 1: B_CAPITAL
+ section 1: Capitalization
  section 2: F_NONMIL units
  section 3: other units
  section 4: wonders
@@ -583,7 +583,7 @@
       pitem->section = unit_type_flag(id, F_NONMIL) ? 2 : 3;
     } else {
       name = get_impr_name_ex(pcity, id);
-      if (id == B_CAPITAL) {
+      if (building_has_effect(id, EFT_PROD_TO_GOLD)) {
        cost = -1;
        pitem->section = 1;
       } else {
@@ -713,7 +713,7 @@
   impr_type_iterate(id) {
     bool can_build = can_player_build_improvement(game.player_ptr, id);
     bool can_eventually_build =
-       could_player_eventually_build_improvement(game.player_ptr, id);
+       can_player_eventually_build_improvement(game.player_ptr, id);
 
     /* If there's a city, can the city build the improvement? */
     if (pcity) {
Index: client/helpdata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/helpdata.c,v
retrieving revision 1.73
diff -u -r1.73 helpdata.c
--- client/helpdata.c   31 Aug 2004 04:40:48 -0000      1.73
+++ client/helpdata.c   1 Sep 2004 01:53:04 -0000
@@ -533,7 +533,8 @@
   
   assert(buf&&user_text);
   buf[0] = '\0';
-  if(which==B_MANHATTEN && num_role_units(F_NUCLEAR)>0) {
+  if(building_has_effect(which, EFT_ENABLE_NUKE)
+      && num_role_units(F_NUCLEAR)>0) {
     int u, t;
     u = get_role_unit(F_NUCLEAR, 0);
     assert(u<game.num_unit_types);
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.400
diff -u -r1.400 packhand.c
--- client/packhand.c   31 Aug 2004 04:40:48 -0000      1.400
+++ client/packhand.c   1 Sep 2004 01:53:05 -0000
@@ -699,10 +699,10 @@
                            ARRAY_SIZE(pcity->improvements));
   }
 
-  update_improvement_from_packet(pcity, B_PALACE, packet->capital,
-                                 &need_effect_update);
-  update_improvement_from_packet(pcity, B_CITY, packet->walls,
-                                 &need_effect_update);
+  update_improvement_from_packet(pcity, game.palace_building,
+                                packet->capital, &need_effect_update);
+  update_improvement_from_packet(pcity, game.land_defend_building,
+                                packet->walls, &need_effect_update);
 
   if (city_is_new) {
     init_worklist(&pcity->worklist);
@@ -1367,6 +1367,20 @@
   game.nuclearwinter=pinfo->nuclearwinter;
   game.cooling=pinfo->cooling;
   if (!can_client_change_view()) {
+    /*
+     * 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, "Cannot find any palace building");
+    }
+
+    game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND);
+    if (game.land_defend_building == B_LAST) {
+      freelog(LOG_FATAL, "Cannot find any land defend building");
+    }
+
     improvement_status_init(game.improvements,
                            ARRAY_SIZE(game.improvements));
 
@@ -2155,6 +2169,8 @@
   tilespec_free_city_tiles(game.styles_count);
   ruleset_data_free();
 
+  ruleset_cache_init();
+
   game.aqueduct_size = packet->aqueduct_size;
   game.sewer_size = packet->sewer_size;
   game.add_to_size_limit = packet->add_to_size_limit;
@@ -2194,6 +2210,8 @@
     mystrlcpy(team_get_by_id(i)->name, packet->team_name[i],
               MAX_LEN_NAME);
   }
+
+  game.default_building = packet->default_building;
 }
 
 /**************************************************************************
@@ -2328,12 +2346,6 @@
   T(equiv_repl, equiv_repl_count, B_LAST);
 #undef T
 
-  b->effect = fc_malloc(sizeof(*b->effect) * (p->effect_count + 1));
-  for (i = 0; i < p->effect_count; i++) {
-    b->effect[i] = p->effect[i];
-  }
-  b->effect[p->effect_count].type = EFT_LAST;
-
 #ifdef DEBUG
   if(p->id == game.num_impr_types-1) {
     impr_type_iterate(id) {
@@ -2384,75 +2396,6 @@
       freelog(LOG_DEBUG, "  upkeep      %2d", b->upkeep);
       freelog(LOG_DEBUG, "  sabotage   %3d", b->sabotage);
       freelog(LOG_DEBUG, "  effect...");
-      for (inx = 0; b->effect[inx].type != EFT_LAST; inx++) {
-       char buf[1024], *ptr;
-       ptr = buf;
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " %d/%s",
-                   b->effect[inx].type,
-                   effect_type_name(b->effect[inx].type));
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " range=%d/%s",
-                   b->effect[inx].range,
-                   effect_range_name(b->effect[inx].range));
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " amount=%d",
-                   b->effect[inx].amount);
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " survives=%d",
-                   b->effect[inx].survives);
-       ptr = strchr(ptr, '\0');
-       freelog(LOG_DEBUG, "   %2d. %s", inx, buf);
-       ptr = buf;
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_bldg=%d/%s",
-                   b->effect[inx].cond_bldg,
-                   (b->effect[inx].cond_bldg == B_LAST) ?
-                   "Uncond." :
-                   improvement_types[b->effect[inx].cond_bldg].name);
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_gov=%d/%s",
-                   b->effect[inx].cond_gov,
-                   (b->effect[inx].cond_gov == game.government_count) ?
-                   "Uncond." :
-                   get_government_name(b->effect[inx].cond_gov));
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_adv=%d/%s",
-                   b->effect[inx].cond_adv,
-                   (b->effect[inx].cond_adv == A_NONE) ?
-                   "Uncond." :
-                   (b->effect[inx].cond_adv == A_LAST) ?
-                   "Never" :
-                   advances[b->effect[inx].cond_adv].name);
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_eff=%d/%s",
-                   b->effect[inx].cond_eff,
-                   (b->effect[inx].cond_eff == EFT_LAST) ?
-                   "Uncond." :
-                   effect_type_name(b->effect[inx].cond_eff));
-       ptr = strchr(ptr, '\0');
-       freelog(LOG_DEBUG, "       %s", buf);
-       ptr = buf;
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_unit=%d/%s",
-                   b->effect[inx].aff_unit,
-                   (b->effect[inx].aff_unit == UCL_LAST) ?
-                   "All" :
-                   unit_class_name(b->effect[inx].aff_unit));
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_terr=%d/%s",
-                   b->effect[inx].aff_terr,
-                   (b->effect[inx].aff_terr == T_NONE) ? "None"
-                   : ((b->effect[inx].aff_terr == T_UNKNOWN) ? "All"
-                      : get_terrain_name(b->effect[inx].aff_terr)));
-       ptr = strchr(ptr, '\0');
-       my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_spec=%04X/%s",
-                   b->effect[inx].aff_spec,
-                   (b->effect[inx].aff_spec == 0) ?
-                   "None" :
-                   (b->effect[inx].aff_spec == S_ALL) ?
-                   "All" :
-                   get_special_name(b->effect[inx].aff_spec));
-       ptr = strchr(ptr, '\0');
-       freelog(LOG_DEBUG, "       %s", buf);
-      }
       freelog(LOG_DEBUG, "  variant     %2d", b->variant);     /* FIXME: 
remove when gen-impr obsoletes */
       freelog(LOG_DEBUG, "  helptext    %s", b->helptext);
     } impr_type_iterate_end;
@@ -2975,3 +2918,30 @@
 {
   freelog(LOG_VERBOSE, "server shutdown");
 }
+
+/**************************************************************************
+  Add group data to ruleset cache.  
+**************************************************************************/
+void handle_ruleset_cache_group(struct packet_ruleset_cache_group *packet)
+{
+  struct eff_group *pgroup;
+  int i;
+
+  pgroup = eff_group_new(packet->name);
+
+  for (i = 0; i < packet->num_elements; i++) {
+    eff_group_add(pgroup, packet->improvements[i],
+                 packet->ranges[i], packet->survives[i]);
+  }
+}
+
+/**************************************************************************
+  Add effect data to ruleset cache.  
+**************************************************************************/
+void handle_ruleset_cache_effect(struct packet_ruleset_cache_effect *packet)
+{
+  ruleset_cache_add(packet->id, packet->eff, packet->range, packet->survives,
+                   packet->value, packet->req, packet->arg,
+                   packet->group);
+}
+
Index: client/repodlgs_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/repodlgs_common.c,v
retrieving revision 1.12
diff -u -r1.12 repodlgs_common.c
--- client/repodlgs_common.c    29 Aug 2004 12:36:12 -0000      1.12
+++ client/repodlgs_common.c    1 Sep 2004 01:53:05 -0000
@@ -321,7 +321,7 @@
     if (!pcity->did_sell && city_got_building(pcity, impr)
        && (!obsolete_only
            || improvement_obsolete(game.player_ptr, impr)
-           || wonder_replacement(pcity, impr))) {
+           || building_replaced(pcity, impr))) {
       count++;
       gold += impr_sell_gold(impr);
       city_sell_improvement(pcity, impr);
Index: client/text.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/text.c,v
retrieving revision 1.9
diff -u -r1.9 text.c
--- client/text.c       13 Aug 2004 15:26:50 -0000      1.9
+++ client/text.c       1 Sep 2004 01:53:05 -0000
@@ -711,34 +711,18 @@
 const char *get_happiness_buildings(const struct city *pcity)
 {
   int faces = 0;
-  struct government *g = get_gov_pcity(pcity);
+  struct building_vector sources;
   INIT;
 
   add_line(_("Buildings: "));
-  if (city_got_building(pcity, B_TEMPLE)) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_TEMPLE));
-  }
-  if (city_got_building(pcity, B_COURTHOUSE) && g->corruption_level == 0) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_COURTHOUSE));
-  }
-  if (city_got_building(pcity, B_COLOSSEUM)) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_COLOSSEUM));
-  }
-  if (faces > 2) {
-    /* Hack to get wrapping right. */
-    add(_("\n              "));
-  }
-  if (city_got_effect(pcity, B_CATHEDRAL)) {
+
+  sources = get_city_bonus_sources(pcity, EFT_MAKE_CONTENT);
+  building_vector_iterate(&sources, pbldg) {
     faces++;
-    add("%s", get_improvement_name(B_CATHEDRAL));
-    if (!city_got_building(pcity, B_CATHEDRAL)) {
-      add(_("(%s)"), get_improvement_name(B_MICHELANGELO));
-    }
-    add(_(". "));
-  }
+    add(_("%s. "), get_improvement_name(*pbldg));
+  } building_vector_iterate_end;
+  building_vector_free(&sources);
+
   if (faces == 0) {
     add(_("None. "));
   }
@@ -752,31 +736,31 @@
 const char *get_happiness_wonders(const struct city *pcity)
 {
   int faces = 0;
+  struct building_vector sources;
   INIT;
 
   add_line(_("Wonders: "));
 
-  if (city_affected_by_wonder(pcity, B_HANGING)) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_HANGING));
-  }
-  if (city_affected_by_wonder(pcity, B_BACH)) {
+  sources = get_city_bonus_sources(pcity, EFT_MAKE_HAPPY);
+  building_vector_iterate(&sources, pbldg) {
     faces++;
-    add(_("%s. "), get_improvement_name(B_BACH));
-  }
-  /* hack for eliminating gtk_set_line_wrap() -mck */
-  if (faces > 1) {
-    /* sizeof("Wonders: ") */
-    add(_("\n              "));
-  }
-  if (city_affected_by_wonder(pcity, B_SHAKESPEARE)) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_SHAKESPEARE));
-  }
-  if (city_affected_by_wonder(pcity, B_CURE)) {
-    faces++;
-    add(_("%s. "), get_improvement_name(B_CURE));
-  }
+    add(_("%s. "), get_improvement_name(*pbldg));
+  } building_vector_iterate_end;
+  building_vector_free(&sources);
+
+  sources = get_city_bonus_sources(pcity, EFT_FORCE_CONTENT);
+  building_vector_iterate(&sources, pbldg) {
+    faces++;
+    add(_("%s. "), get_improvement_name(*pbldg));
+  } building_vector_iterate_end;
+  building_vector_free(&sources);
+
+  sources = get_city_bonus_sources(pcity, EFT_NO_UNHAPPY);
+  building_vector_iterate(&sources, pbldg) {
+    faces++;
+    add(_("%s. "), get_improvement_name(*pbldg));
+  } building_vector_iterate_end;
+  building_vector_free(&sources);
 
   if (faces == 0) {
     add(_("None. "));
Index: common/city.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.c,v
retrieving revision 1.239
diff -u -r1.239 city.c
--- common/city.c       31 Aug 2004 04:40:50 -0000      1.239
+++ common/city.c       1 Sep 2004 01:53:06 -0000
@@ -263,54 +263,6 @@
 }
 
 /**************************************************************************
- FIXME: This should be replaced in the near future with
- improvment_redundant()
-**************************************************************************/
-bool wonder_replacement(const struct city *pcity, Impr_Type_id id)
-{
-  if(is_wonder(id)) return FALSE;
-  switch (id) {
-  case B_BARRACKS:
-  case B_BARRACKS2:
-  case B_BARRACKS3:
-    if (city_affected_by_wonder(pcity, B_SUNTZU))
-      return TRUE;
-    break;
-  case B_GRANARY:
-    if (improvement_variant(B_PYRAMIDS)==0
-       && city_affected_by_wonder(pcity, B_PYRAMIDS))
-      return TRUE;
-    break;
-  case B_CATHEDRAL:
-    if (improvement_variant(B_MICHELANGELO)==0
-       && city_affected_by_wonder(pcity, B_MICHELANGELO))
-      return TRUE;
-    break;
-  case B_CITY:  
-    if (city_affected_by_wonder(pcity, B_WALL))
-      return TRUE;
-    break;
-  case B_HYDRO:
-  case B_POWER:
-  case B_NUCLEAR:
-    if (city_affected_by_wonder(pcity, B_HOOVER))
-      return TRUE;
-    break;
-  case B_POLICE:
-    if (city_affected_by_wonder(pcity, B_WOMENS))
-      return TRUE;
-    break;
-  case B_RESEARCH:
-    if (city_affected_by_wonder(pcity, B_SETI))
-      return TRUE;
-    break;
-  default:
-    break;
-  }
-  return FALSE;
-}
-
-/**************************************************************************
   Return the extended name of the building.
 **************************************************************************/
 const char *get_impr_name_ex(const struct city *pcity, Impr_Type_id id)
@@ -399,13 +351,14 @@
 }
 
 /**************************************************************************
- Will this city ever be able to build this improvement?
- Doesn't check for building prereqs
+  Return whether given city can build given improvement, ignoring whether
+  improvement is obsolete.
 **************************************************************************/
-bool can_eventually_build_improvement(const struct city *pcity, Impr_Type_id 
id)
+bool can_build_improvement_direct(const struct city *pcity, Impr_Type_id id)
 {
-  /* also does an improvement_exists() */
-  if (!could_player_eventually_build_improvement(city_owner(pcity),id)) {
+  struct impr_type *impr;
+
+  if (!can_player_build_improvement_direct(city_owner(pcity), id)) {
     return FALSE;
   }
 
@@ -413,24 +366,7 @@
     return FALSE;
   }
 
-  if (!city_has_terr_spec_gate(pcity,id)) {
-    return FALSE;
-  }
-
-  return !improvement_redundant(city_owner(pcity),pcity, id, TRUE);
-}
-
-/**************************************************************************
- Could this improvment be built in the city, without checking if the
- owner has the required tech, but if all other pre reqs are fulfiled? 
- modularized so the AI can choose the tech it wants -- Syela 
-**************************************************************************/
-static bool could_build_improvement(const struct city *pcity, 
-                                    Impr_Type_id id)
-{
-  struct impr_type *impr;
-
-  if (!can_eventually_build_improvement(pcity, id)) {
+  if (!city_has_terr_spec_gate(pcity, id)) {
     return FALSE;
   }
 
@@ -438,7 +374,7 @@
 
   /* The building pre req */
   if (impr->bldg_req != B_LAST) {
-    if (!city_got_building(pcity,impr->bldg_req)) {
+    if (!city_got_building(pcity, impr->bldg_req)) {
       return FALSE;
     }
   }
@@ -447,19 +383,37 @@
 }
 
 /**************************************************************************
-  Can this improvement get built in this city by the player who owns it?
+  Return whether given city can build given unit; returns 0 if unit is 
+  obsolete.
 **************************************************************************/
 bool can_build_improvement(const struct city *pcity, Impr_Type_id id)
-{
-  struct player *p = city_owner(pcity);
+{  
+  if (!can_build_improvement_direct(pcity, id)) {
+    return FALSE;
+  }
+  if (improvement_obsolete(city_owner(pcity), id)) {
+    return FALSE;
+  }
+  return TRUE;
+}
 
-  if (!improvement_exists(id)) {
+/**************************************************************************
+  Return whether player can eventually build given improvement in the city;
+  returns 0 if improvement can never possibly be built in this city.
+**************************************************************************/
+bool can_eventually_build_improvement(const struct city *pcity,
+                                     Impr_Type_id id)
+{
+  /* Can the _player_ ever build this improvement? */
+  if (!can_player_eventually_build_improvement(city_owner(pcity), id)) {
     return FALSE;
   }
-  if (!player_knows_improvement_tech(p, id)) {
+
+  if (!city_has_terr_spec_gate(pcity, id)) {
     return FALSE;
   }
-  return could_build_improvement(pcity, id);
+
+  return TRUE;
 }
 
 /**************************************************************************
@@ -565,11 +519,10 @@
     return 0;
   if (is_wonder(i))
     return 0;
-  if (improvement_types[i].upkeep == 1 &&
-      city_affected_by_wonder(pcity, B_ASMITHS)) 
+  if (improvement_types[i].upkeep <=
+      get_city_bonus(pcity, EFT_UPKEEP_FREE))
     return 0;
-  if (government_has_flag(get_gov_pcity(pcity), G_CONVERT_TITHES_TO_MONEY)
-      && (i == B_TEMPLE || i == B_COLOSSEUM || i == B_CATHEDRAL)) {
+  if (get_building_bonus(pcity, i, EFT_NO_UPKEEP)) {
     return 0;
   }
   
@@ -587,6 +540,7 @@
 {
   enum tile_special_type spec_t = map_get_special(map_x, map_y);
   Terrain_type_id tile_t = map_get_terrain(map_x, map_y);
+  struct tile *ptile = map_get_tile(map_x, map_y);
   int s;
 
   if (contains_special(spec_t, S_SPECIAL_1)) {
@@ -610,17 +564,14 @@
     int before_penalty = (is_celebrating ? g->celeb_shields_before_penalty
                          : g->shields_before_penalty);
 
-    if (city_affected_by_wonder(pcity, B_RICHARDS)) {
-      s++;
-    }
-    if (is_ocean(tile_t) && city_got_building(pcity, B_OFFSHORE)) {
-      s++;
-    }
+    s += get_city_tile_bonus(pcity, ptile, EFT_PROD_ADD_TILE);
 
     /* government shield bonus & penalty */
     if (s > 0) {
       s += (is_celebrating ? g->celeb_shield_bonus : g->shield_bonus);
+      s += get_city_tile_bonus(pcity, ptile, EFT_PROD_INC_TILE);
     }
+
     if (before_penalty > 0 && s > before_penalty) {
       s--;
     }
@@ -692,6 +643,7 @@
 {
   enum tile_special_type spec_t = map_get_special(map_x, map_y);
   Terrain_type_id tile_t = map_get_terrain(map_x, map_y);
+  struct tile *ptile = map_get_tile(map_x, map_y);
   int t;
 
   if (contains_special(spec_t, S_SPECIAL_1)) {
@@ -705,50 +657,46 @@
   if (contains_special(spec_t, S_RIVER) && !is_ocean(tile_t)) {
     t += terrain_control.river_trade_incr;
   }
+
   if (contains_special(spec_t, S_ROAD)) {
     t += get_tile_type(tile_t)->road_trade_incr;
   }
-  if (t > 0) {
-    if (contains_special(spec_t, S_RAILROAD)) {
-      t += (t * terrain_control.rail_trade_bonus) / 100;
-    }
-
-    /* Civ1 specifically documents that Railroad trade increase is before 
-     * Democracy/Republic [government in general now -- SKi] bonus  -AJS */
-    if (pcity) {
-      struct government *g = get_gov_pcity(pcity);
-      int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty
-                           : g->trade_before_penalty);
 
-      if (t > 0) {
-       t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus);
-      }
+  if (contains_special(spec_t, S_RAILROAD)) {
+    t += (t * terrain_control.rail_trade_bonus) / 100;
+  }
 
-      if (city_affected_by_wonder(pcity, B_COLLOSSUS)) {
-       t++;
-      }
+  /* Civ1 specifically documents that Railroad trade increase is before 
+   * Democracy/Republic [government in general now -- SKi] bonus  -AJS */
+  if (pcity) {
+    struct government *g = get_gov_pcity(pcity);
+    int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty
+                         : g->trade_before_penalty);
 
-      if (contains_special(spec_t, S_ROAD)
-         && city_got_building(pcity, B_SUPERHIGHWAYS)) {
-       t += (t * terrain_control.road_superhighway_trade_bonus) / 100;
-      }
+    t += get_city_tile_bonus(pcity, ptile, EFT_TRADE_ADD_TILE);
 
-      /* government trade penalty -- SKi */
-      if (before_penalty > 0 && t > before_penalty) {
-       t--;
-      }
+    if (t > 0) {
+      t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus);
+      t += get_city_bonus(pcity, EFT_TRADE_INC_TILE);
     }
 
-    if (contains_special(spec_t, S_POLLUTION)) {
-      /* The trade here is dirty */
-      t -= (t * terrain_control.pollution_trade_penalty) / 100;
-    }
+    t += (t * get_city_tile_bonus(pcity, ptile, EFT_TRADE_PER_TILE)) / 100;
 
-    if (contains_special(spec_t, S_FALLOUT)) {
-      t -= (t * terrain_control.fallout_trade_penalty) / 100;
+    /* government trade penalty -- SKi */
+    if (before_penalty > 0 && t > before_penalty) {
+      t--;
     }
   }
 
+  if (contains_special(spec_t, S_POLLUTION)) {
+    /* The trade here is dirty */
+    t -= (t * terrain_control.pollution_trade_penalty) / 100;
+  }
+
+  if (contains_special(spec_t, S_FALLOUT)) {
+    t -= (t * terrain_control.fallout_trade_penalty) / 100;
+  }
+
   if (pcity && is_city_center(city_x, city_y)) {
     t = MAX(t, game.rgame.min_city_center_trade);
   }
@@ -806,36 +754,43 @@
   const enum tile_special_type spec_t = map_get_special(map_x, map_y);
   const Terrain_type_id tile_t = map_get_terrain(map_x, map_y);
   struct tile_type *type = get_tile_type(tile_t);
+  struct tile tile;
   int f;
   const bool auto_water = (pcity && is_city_center(city_x, city_y)
                           && tile_t == type->irrigation_result
                           && terrain_control.may_irrigate);
 
-  if (contains_special(spec_t, S_SPECIAL_1)) {
-    f = get_tile_type(tile_t)->food_special_1;
-  } else if (contains_special(spec_t, S_SPECIAL_2)) {
-    f = get_tile_type(tile_t)->food_special_2;
+  /* create dummy tile which has the city center bonuses. */
+  tile.terrain = tile_t;
+  tile.special = spec_t;
+
+  if (auto_water) {
+    /* The center tile is auto-irrigated. */
+    tile.special |= S_IRRIGATION;
+
+    if (player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) {
+      tile.special |= S_FARMLAND;
+    }
+  }
+
+  if (contains_special(tile.special, S_SPECIAL_1)) {
+    f = type->food_special_1;
+  } else if (contains_special(tile.special, S_SPECIAL_2)) {
+    f = type->food_special_2;
   } else {
-    f = get_tile_type(tile_t)->food;
+    f = type->food;
   }
 
-  if (contains_special(spec_t, S_IRRIGATION) || auto_water) {
-    /* The center tile is auto-irrigated. */
+  if (contains_special(tile.special, S_IRRIGATION)) {
     f += type->irrigation_food_incr;
+  }
 
-    /* Farmland only affects cities with supermarkets.  The center tile is
-     * auto-irrigated. */
-    if (pcity
-       && (contains_special(spec_t, S_FARMLAND)
-           || (auto_water
-               && player_knows_techs_with_flag(city_owner(pcity),
-                                               TF_FARMLAND)))
-       && city_got_building(pcity, B_SUPERMARKET)) {
-      f += (f * terrain_control.farmland_supermarket_food_bonus) / 100;
-    }
+  /* Farmland only affects cities with supermarkets. */
+  if (pcity) {
+    f += (f * get_city_tile_bonus(pcity, &tile, EFT_FOOD_PER_TILE)) / 100;
   }
 
-  if (contains_special(spec_t, S_RAILROAD)) {
+  if (contains_special(tile.special, S_RAILROAD)) {
     f += (f * terrain_control.rail_food_bonus) / 100;
   }
 
@@ -844,23 +799,23 @@
     int before_penalty = (is_celebrating ? g->celeb_food_before_penalty
                          : g->food_before_penalty);
 
-    if (is_ocean(tile_t) && city_got_building(pcity, B_HARBOUR)) {
-      f++;
-    }
+    f += get_city_tile_bonus(pcity, &tile, EFT_FOOD_ADD_TILE);
 
     if (f > 0) {
       f += (is_celebrating ? g->celeb_food_bonus : g->food_bonus);
+      f += get_city_bonus(pcity, EFT_FOOD_INC_TILE);
     }
+
     if (before_penalty > 0 && f > before_penalty) {
       f--;
     }
   }
 
-  if (contains_special(spec_t, S_POLLUTION)) {
+  if (contains_special(tile.special, S_POLLUTION)) {
     /* The food here is yucky */
     f -= (f * terrain_control.pollution_food_penalty) / 100;
   }
-  if (contains_special(spec_t, S_FALLOUT)) {
+  if (contains_special(tile.special, S_FALLOUT)) {
     f -= (f * terrain_control.fallout_food_penalty) / 100;
   }
 
@@ -1123,22 +1078,12 @@
 }
 
 /**************************************************************************
- Whether a city has an improvement, or the same effect via a wonder.
- (The Impr_Type_id should be an improvement, not a wonder.)
- Note also: city_got_citywalls(), and server/citytools:city_got_barracks()
-**************************************************************************/
-bool city_got_effect(const struct city *pcity, Impr_Type_id id)
-{
-  return city_got_building(pcity, id) || wonder_replacement(pcity, id);
-}
-
-/**************************************************************************
   Return TRUE iff this city is its nation's capital.  The capital city is
   special-cased in a number of ways.
 **************************************************************************/
 bool is_capital(const struct city *pcity)
 {
-  return city_got_building(pcity, B_PALACE);
+  return (get_city_bonus(pcity, EFT_CAPITAL_CITY) != 0);
 }
 
 /**************************************************************************
@@ -1146,80 +1091,7 @@
 **************************************************************************/
 bool city_got_citywalls(const struct city *pcity)
 {
-  if (city_got_building(pcity, B_CITY))
-    return TRUE;
-  return (city_affected_by_wonder(pcity, B_WALL));
-}
-
-/**************************************************************************
-  Return TRUE if the wonder's effect applies to this city.  This is only
-  used for some wonder checks; others are done manually.
-**************************************************************************/
-bool city_affected_by_wonder(const struct city *pcity, Impr_Type_id id)
-{
-  struct city *tmp;
-  if (!improvement_exists(id))
-    return FALSE;
-  if (!is_wonder(id) || wonder_obsolete(id))
-    return FALSE;
-  if (city_got_building(pcity, id))
-    return TRUE;
-  
-  /* For Manhatten it can be owned by anyone, and it doesn't matter
-   * whether it is destroyed or not.
-   *
-   * (The same goes for Apollo, with respect to building spaceship parts,
-   * but not for getting the map effect.  This function only returns true
-   * for Apollo for the owner of a non-destroyed Apollo; for building
-   * spaceship parts just check (game.global_wonders[id] != 0).
-   * (Actually, this function is not currently used for either Manhatten
-   * or Apollo.))
-   *
-   * Otherwise the player who owns the city needs to have it to
-   * get the effect.
-   */
-  if (id==B_MANHATTEN) 
-    return (game.global_wonders[id] != 0);
-  
-  tmp = player_find_city_by_id(city_owner(pcity), game.global_wonders[id]);
-  if (!tmp)
-    return FALSE;
-  switch (id) {
-  case B_ASMITHS:
-  case B_APOLLO:
-  case B_CURE:
-  case B_GREAT:
-  case B_WALL:
-  case B_HANGING:
-  case B_ORACLE:
-  case B_UNITED:
-  case B_WOMENS:
-  case B_DARWIN:
-  case B_LIGHTHOUSE:
-  case B_MAGELLAN:
-  case B_MICHELANGELO:
-  case B_SETI:
-  case B_PYRAMIDS:
-  case B_LIBERTY:
-  case B_SUNTZU:
-    return TRUE;
-  case B_ISAAC:
-  case B_COPERNICUS:
-  case B_SHAKESPEARE:
-  case B_COLLOSSUS:
-  case B_RICHARDS:
-    return FALSE;
-  case B_HOOVER:
-  case B_BACH:
-    if (improvement_variant(id)==1) {
-      return (map_get_continent(tmp->x, tmp->y) ==
-             map_get_continent(pcity->x, pcity->y));
-    } else {
-      return TRUE;
-    }
-  default:
-    return FALSE;
-  }
+  return (get_city_bonus(pcity, EFT_LAND_DEFEND) > 0);
 }
 
 /**************************************************************************
@@ -1560,10 +1432,14 @@
 ****************************************************************************/
 bool city_can_grow_to(const struct city *pcity, int pop_size)
 {
-  return (pop_size <= game.aqueduct_size
-         || (pop_size <= game.sewer_size
-             && city_got_building(pcity, B_AQUEDUCT))
-         || city_got_building(pcity, B_SEWER));
+  if (get_city_bonus(pcity, EFT_SIZE_UNLIMIT)) {
+    return TRUE;
+  } else {
+    int max_size;
+                                                                               
+    max_size = game.aqueduct_size + get_city_bonus(pcity, EFT_SIZE_ADJ);
+    return (pop_size <= max_size);
+  }
 }
 
 /**************************************************************************
@@ -1706,23 +1582,7 @@
 **************************************************************************/
 int get_city_shield_bonus(const struct city *pcity)
 {
-  int shield_bonus = 100;
-
-  if (city_got_building(pcity, B_FACTORY)) {
-    shield_bonus += 50;
-    if (city_got_building(pcity, B_MFG)) {
-      shield_bonus += 50;
-    }
-
-    if (city_affected_by_wonder(pcity, B_HOOVER) ||
-       city_got_building(pcity, B_POWER) ||
-       city_got_building(pcity, B_HYDRO) ||
-       city_got_building(pcity, B_NUCLEAR)) {
-      shield_bonus = 100 + (3 * (shield_bonus - 100)) / 2;
-    }
-  }
-
-  return shield_bonus;
+  return (100 + get_city_bonus(pcity, EFT_PROD_BONUS));
 }
 
 /**************************************************************************
@@ -1730,19 +1590,7 @@
 **************************************************************************/
 int get_city_tax_bonus(const struct city *pcity)
 {
-  int tax_bonus = 100;
-
-  if (city_got_building(pcity, B_MARKETPLACE)) {
-    tax_bonus += 50;
-    if (city_got_building(pcity, B_BANK)) {
-      tax_bonus += 50;
-      if (city_got_building(pcity, B_STOCK)) {
-       tax_bonus += 50;
-      }
-    }
-  }
-
-  return tax_bonus;
+  return (100 + get_city_bonus(pcity, EFT_TAX_BONUS));
 }
 
 /**************************************************************************
@@ -1750,8 +1598,7 @@
 **************************************************************************/
 int get_city_luxury_bonus(const struct city *pcity)
 {
-  /* Currently the luxury bonus is equivalent to the tax bonus. */
-  return get_city_tax_bonus(pcity);
+  return (100 + get_city_bonus(pcity, EFT_LUXURY_BONUS));
 }
 
 /**************************************************************************
@@ -1767,16 +1614,8 @@
     return 0;
   }
 
-  if (city_got_building(pcity, B_TEMPLE))
-    tithes_bonus += get_temple_power(pcity);
-  if (city_got_building(pcity, B_COLOSSEUM))
-    tithes_bonus += get_colosseum_power(pcity);
-  if (city_got_effect(pcity, B_CATHEDRAL))
-    tithes_bonus += get_cathedral_power(pcity);
-  if (city_affected_by_wonder(pcity, B_BACH))
-    tithes_bonus += 2;
-  if (city_affected_by_wonder(pcity, B_CURE))
-    tithes_bonus += 1;
+  tithes_bonus += get_city_bonus(pcity, EFT_MAKE_CONTENT);
+  tithes_bonus += get_city_bonus(pcity, EFT_FORCE_CONTENT);
 
   return tithes_bonus;
 }
@@ -1786,23 +1625,10 @@
 **************************************************************************/
 int get_city_science_bonus(const struct city *pcity)
 {
-  int science_bonus = 100;
+  int science_bonus;
+
+  science_bonus = 100 + get_city_bonus(pcity, EFT_SCIENCE_BONUS);
 
-  if (city_got_building(pcity, B_LIBRARY)) {
-    science_bonus += 50;
-    if (city_got_building(pcity, B_UNIVERSITY)) {
-      science_bonus += 50;
-    }
-    if (city_got_effect(pcity, B_RESEARCH)) {
-      science_bonus += 50;
-    }
-  }
-  if (city_affected_by_wonder(pcity, B_COPERNICUS)) {
-    science_bonus += 50;
-  }
-  if (city_affected_by_wonder(pcity, B_ISAAC)) {
-    science_bonus += 100;
-  }
   if (government_has_flag(get_gov_pcity(pcity), G_REDUCED_RESEARCH)) {
     science_bonus /= 2;
   }
@@ -1880,6 +1706,7 @@
   /* this is the place to set them */
   pcity->luxury_bonus = get_city_luxury_bonus(pcity);
   pcity->tax_bonus = get_city_tax_bonus(pcity);
+  pcity->luxury_bonus = get_city_luxury_bonus(pcity);
   pcity->science_bonus = get_city_science_bonus(pcity);
   pcity->shield_bonus = get_city_shield_bonus(pcity);
 
@@ -2012,21 +1839,11 @@
 **************************************************************************/
 static inline void citizen_content_buildings(struct city *pcity)
 {
-  struct government *g = get_gov_pcity(pcity);
   int faces = 0;
   happy_copy(pcity, 1);
 
-  if (city_got_building(pcity, B_TEMPLE)) {
-    faces += get_temple_power(pcity);
-  }
-  if (city_got_building(pcity, B_COURTHOUSE) && g->corruption_level == 0) {
-    faces++;
-  }
+  faces += get_city_bonus(pcity, EFT_MAKE_CONTENT);
 
-  if (city_got_building(pcity, B_COLOSSEUM))
-    faces += get_colosseum_power(pcity);
-  if (city_got_effect(pcity, B_CATHEDRAL))
-    faces += get_cathedral_power(pcity);
   /* make people content (but not happy):
      get rid of angry first, then make unhappy content. */
   while (faces > 0 && pcity->ppl_angry[2] > 0) {
@@ -2046,14 +1863,13 @@
 **************************************************************************/
 static inline void citizen_happy_wonders(struct city *pcity)
 {
-  int bonus = 0;
+  int bonus = 0, mod;
 
   happy_copy(pcity, 3);
 
-  if (city_affected_by_wonder(pcity, B_HANGING)) {
-    bonus += 1;
-    if (city_got_building(pcity, B_HANGING))
-      bonus += 2;
+  if ((mod = get_city_bonus(pcity, EFT_MAKE_HAPPY)) > 0) {
+    bonus += mod;
+
     while (bonus > 0 && pcity->ppl_content[4] > 0) {
       pcity->ppl_content[4]--;
       pcity->ppl_happy[4]++;
@@ -2062,10 +1878,9 @@
          will let it make unhappy content */
     }
   }
-  if (city_affected_by_wonder(pcity, B_BACH))
-    bonus += 2;
-  if (city_affected_by_wonder(pcity, B_CURE))
-    bonus += 1;
+
+  bonus += get_city_bonus(pcity, EFT_FORCE_CONTENT);
+
   /* get rid of angry first, then make unhappy content */
   while (bonus > 0 && pcity->ppl_angry[4] > 0) {
     pcity->ppl_angry[4]--;
@@ -2078,7 +1893,7 @@
     bonus--;
   }
 
-  if (city_affected_by_wonder(pcity, B_SHAKESPEARE)) {
+  if (get_city_bonus(pcity, EFT_NO_UNHAPPY)) {
     pcity->ppl_content[4] += pcity->ppl_unhappy[4] + pcity->ppl_angry[4];
     pcity->ppl_unhappy[4] = 0;
     pcity->ppl_angry[4] = 0;
@@ -2110,22 +1925,22 @@
 static inline void set_pollution(struct city *pcity)
 {
   struct player *pplayer = city_owner(pcity);
+  int mod;
 
   pcity->pollution = pcity->shield_prod;
-  if (city_got_building(pcity, B_RECYCLING)) {
-    pcity->pollution /= 3;
-  } else if (city_got_building(pcity, B_HYDRO) ||
-            city_affected_by_wonder(pcity, B_HOOVER) ||
-            city_got_building(pcity, B_NUCLEAR)) {
-    pcity->pollution /= 2;
-  }
 
-  if (!city_got_building(pcity, B_MASS)) {
-    pcity->pollution += (pcity->size *
-                        num_known_tech_with_flag
-                        (pplayer, TF_POPULATION_POLLUTION_INC)) / 4;
+  mod = get_city_bonus(pcity, EFT_POLLU_PROD_PCT);
+
+  if (mod > 0) {
+    pcity->pollution /= mod;
   }
 
+  mod = (pcity->size *
+      num_known_tech_with_flag(pplayer, TF_POPULATION_POLLUTION_INC)) / 4;
+  mod -= mod * get_city_bonus(pcity, EFT_POLLU_POP_PCT) / 100;
+
+  pcity->pollution += mod;
+
   pcity->pollution = MAX(0, pcity->pollution - 20);
 }
 
@@ -2187,18 +2002,13 @@
 {
   struct government *g = get_gov_pcity(pcity);
 
-  bool have_police = city_got_effect(pcity, B_POLICE);
-  int variant = improvement_variant(B_WOMENS);
-
   int free_happy = citygov_free_happy(pcity, g);
   int free_shield = citygov_free_shield(pcity, g);
   int free_food = citygov_free_food(pcity, g);
   int free_gold = citygov_free_gold(pcity, g);
 
-  if (variant == 0 && have_police) {
-    /* ??  This does the right thing for normal Republic and Democ -- dwp */
-    free_happy += g->unit_happy_cost_factor;
-  }
+  /* ??  This does the right thing for normal Republic and Democ -- dwp */
+  free_happy += get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL);
 
   happy_copy(pcity, 2);
 
@@ -2270,7 +2080,7 @@
        happy_cost = 0;
       }
     }
-    if (happy_cost > 0 && variant == 1 && have_police) {
+    if (happy_cost > 0 && get_city_bonus(pcity, EFT_MAKE_CONTENT_MIL_PER)) {
       happy_cost--;
     }
 
@@ -2415,10 +2225,7 @@
   /* Now calculate the final corruption.  Ordered to reduce integer
    * roundoff errors. */
   val = trade * MAX(dist, 1) * g->corruption_level;
-  if (city_got_building(pcity, B_COURTHOUSE) ||
-      city_got_building(pcity, B_PALACE)) {
-    val /= 2;
-  }
+  val -= (val * get_city_bonus(pcity, EFT_CORRUPT_PCT)) / 100;
   val /= 100 * 100; /* Level is a % multiplied by 100 */
   val = CLIP(trade_penalty, val, trade);
   return val;
@@ -2454,10 +2261,8 @@
   val = shields * MAX(dist, 1) * g->waste_level;
   val /= 100 * 100; /* Level is a % multiplied by 100 */
 
-  if (city_got_building(pcity, B_COURTHOUSE)
-      || city_got_building(pcity, B_PALACE)) {
-    val /= 2;
-  }
+  val -= (val * get_city_bonus(pcity, EFT_WASTE_PCT)) / 100;
+
   val = CLIP(shield_penalty, val, shields);
   return val;
 }
@@ -2477,49 +2282,6 @@
 }
 
 /**************************************************************************
-  Return the power (pacifying effect) of temples in the city.
-**************************************************************************/
-int get_temple_power(const struct city *pcity)
-{
-  struct player *p = city_owner(pcity);
-  int power = 1;
-  if (get_invention(p, game.rtech.temple_plus) == TECH_KNOWN)
-    power = 2;
-  if (city_affected_by_wonder(pcity, B_ORACLE))
-    power *= 2;
-  return power;
-}
-
-/**************************************************************************
-  Return the power (pacifying effect) of cathedrals in the city.
-**************************************************************************/
-int get_cathedral_power(const struct city *pcity)
-{
-  struct player *p = city_owner(pcity);
-  int power = 3;
-  if (get_invention(p, game.rtech.cathedral_minus /*A_COMMUNISM */ ) ==
-      TECH_KNOWN) power--;
-  if (get_invention(p, game.rtech.cathedral_plus /*A_THEOLOGY */ ) ==
-      TECH_KNOWN) power++;
-  if (improvement_variant(B_MICHELANGELO) == 1
-      && city_affected_by_wonder(pcity, B_MICHELANGELO))
-    power *= 2;
-  return power;
-}
-
-/**************************************************************************
-  Return the power (pacifying effect) of colosseums in the city.
-**************************************************************************/
-int get_colosseum_power(const struct city *pcity)
-{
-  struct player *p = city_owner(pcity);
-  int power = 3;
-  if (get_invention(p, game.rtech.colosseum_plus /*A_ELECTRICITY */ ) ==
-      TECH_KNOWN) power++;
-  return power;
-}
-
-/**************************************************************************
  Adds an improvement (and its effects) to a city, and sets the global
  arrays if the improvement has effects and/or an equiv_range that
  extend outside of the city.
@@ -2657,7 +2419,7 @@
       pcity->currently_building = u;
     } else {
       pcity->is_building_unit = FALSE;
-      pcity->currently_building = B_CAPITAL;
+      pcity->currently_building = game.default_building;
     }
   }
   pcity->turn_founded = game.turn;
@@ -2692,6 +2454,7 @@
   pcity->shield_bonus = 100;
   pcity->luxury_bonus = 100;
   pcity->tax_bonus = 100;
+  pcity->luxury_bonus = 100;
   pcity->science_bonus = 100;
 
   pcity->client.occupied = FALSE;
Index: common/city.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/city.h,v
retrieving revision 1.157
diff -u -r1.157 city.h
--- common/city.h       14 Aug 2004 21:29:43 -0000      1.157
+++ common/city.h       1 Sep 2004 01:53:06 -0000
@@ -209,6 +209,9 @@
   int invasion; /* who's coming to kill us, for attack co-ordination */
   int attack, bcost; /* This is also for invasion - total power and value of
                       * all units coming to kill us. */
+
+  int worth; /* Cache city worth here, sum of all weighted incomes */
+  int next_recalc; /* Only recalc every Nth turn */
 };
 
 struct city {
@@ -257,7 +260,7 @@
   int currently_building;
   
   Impr_Status improvements[B_LAST];
-  
+
   struct worklist worklist;
 
   enum city_tile_type city_map[CITY_MAP_SIZE][CITY_MAP_SIZE];
@@ -361,18 +364,17 @@
 
 bool city_has_terr_spec_gate(const struct city *pcity, Impr_Type_id id); 
 int improvement_upkeep(const struct city *pcity, Impr_Type_id i); 
+bool can_build_improvement_direct(const struct city *pcity, Impr_Type_id id);
 bool can_build_improvement(const struct city *pcity, Impr_Type_id id);
-bool can_eventually_build_improvement(const struct city *pcity, Impr_Type_id 
id);
+bool can_eventually_build_improvement(const struct city *pcity,
+                                     Impr_Type_id id);
 bool can_build_unit(const struct city *pcity, Unit_Type_id id);
 bool can_build_unit_direct(const struct city *pcity, Unit_Type_id id);
 bool can_eventually_build_unit(const struct city *pcity, Unit_Type_id id);
 bool city_can_use_specialist(const struct city *pcity, enum specialist_type 
type);
 bool city_got_building(const struct city *pcity,  Impr_Type_id id); 
-bool city_affected_by_wonder(const struct city *pcity, Impr_Type_id id);
-bool city_got_effect(const struct city *pcity, Impr_Type_id id);
 bool is_capital(const struct city *pcity);
 bool city_got_citywalls(const struct city *pcity);
-bool wonder_replacement(const struct city *pcity, Impr_Type_id id);
 int city_change_production_penalty(const struct city *pcity,
                                   int target, bool is_unit);
 int city_turns_to_build(const struct city *pcity, int id, bool id_is_unit,
@@ -486,9 +488,6 @@
 int city_corruption(const struct city *pcity, int trade);
 int city_waste(const struct city *pcity, int shields);
 int city_specialists(const struct city *pcity);                 /* 
elv+tax+scie */
-int get_temple_power(const struct city *pcity);
-int get_cathedral_power(const struct city *pcity);
-int get_colosseum_power(const struct city *pcity);
 int get_city_tax_bonus(const struct city *pcity);
 int get_city_luxury_bonus(const struct city *pcity);
 int get_city_shield_bonus(const struct city *pcity);
Index: common/combat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v
retrieving revision 1.45
diff -u -r1.45 combat.c
--- common/combat.c     25 Aug 2004 18:24:19 -0000      1.45
+++ common/combat.c     1 Sep 2004 01:53:06 -0000
@@ -301,9 +301,9 @@
 **************************************************************************/
 bool unit_really_ignores_citywalls(struct unit *punit)
 {
-  return unit_ignores_citywalls(punit)
+  return (unit_ignores_citywalls(punit)
     || is_air_unit(punit)
-    || (is_sailing_unit(punit) && !(improvement_variant(B_CITY)==1));
+    || is_sailing_unit(punit));
 }
 
 /**************************************************************************
@@ -322,7 +322,7 @@
   square_iterate(x, y, 2, x1, y1) {
     struct city *pcity = map_get_city(x1, y1);
     if (pcity && (!pplayers_allied(city_owner(pcity), owner))
-       && city_got_building(pcity, B_SDI)) return pcity;
+       && get_city_bonus(pcity, EFT_NUKE_PROOF)) return pcity;
   } square_iterate_end;
 
   return NULL;
@@ -406,6 +406,7 @@
                                  int defensepower, bool fortified)
 {
   struct city *pcity = map_get_city(x, y);
+  int mod;
 
   if (unit_type_exists(att_type)) {
     if (unit_type_flag(def_type, F_PIKEMEN)
@@ -419,24 +420,23 @@
     }
          
     if (is_air_unittype(att_type) && pcity) {
-      if (city_got_building(pcity, B_SAM)) {
-       defensepower *= 2;
+      if ((mod = get_city_bonus(pcity, EFT_AIR_DEFEND))) {
+       defensepower *= mod;
       }
-      if (city_got_building(pcity, B_SDI)
+      if ((mod = get_city_bonus(pcity, EFT_MISSILE_DEFEND))
          && unit_type_flag(att_type, F_MISSILE)) {
-       defensepower *= 2;
+       defensepower *= mod;
       }
     } else if (is_water_unit(att_type) && pcity) {
-      if (city_got_building(pcity, B_COASTAL)) {
-       defensepower *= 2;
+      if ((mod = get_city_bonus(pcity, EFT_SEA_DEFEND))) {
+       defensepower *= mod;
       }
     }
     if (!unit_type_flag(att_type, F_IGWALL)
-       && (is_ground_unittype(att_type) || is_heli_unittype(att_type)
-           || (improvement_variant(B_CITY) == 1
-               && is_water_unit(att_type))) && pcity
-       && city_got_citywalls(pcity)) {
-      defensepower *= 3;
+       && (is_ground_unittype(att_type) || is_heli_unittype(att_type))
+        && pcity
+        && (mod = get_city_bonus(pcity, EFT_LAND_DEFEND))) {
+      defensepower *= mod;
     }
 
     if (unit_type_flag(att_type, F_FIGHTER) && is_heli_unittype(def_type)) {
Index: common/dataio.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/dataio.c,v
retrieving revision 1.11
diff -u -r1.11 dataio.c
--- common/dataio.c     2 Jun 2004 19:47:41 -0000       1.11
+++ common/dataio.c     1 Sep 2004 01:53:06 -0000
@@ -712,32 +712,3 @@
   dio_put_uint8(dout, pds->has_reason_to_cancel);
 }
 
-void dio_get_effect(struct data_in *din, struct impr_effect *peffect)
-{
-  dio_get_uint8(din, (int *) &(peffect->type));
-  dio_get_uint8(din, (int *) &(peffect->range));
-  dio_get_sint16(din, &peffect->amount);
-  dio_get_uint8(din, &peffect->survives);
-  dio_get_uint8(din, (int *) &peffect->cond_bldg);
-  dio_get_uint8(din, &peffect->cond_gov);
-  dio_get_uint8(din, &peffect->cond_adv);
-  dio_get_uint8(din, (int *) &(peffect->cond_eff));
-  dio_get_uint8(din, (int *) &(peffect->aff_unit));
-  dio_get_uint8(din, (int *) &(peffect->aff_terr));
-  dio_get_uint16(din, (int *) &(peffect->aff_spec));
-}
-
-void dio_put_effect(struct data_out *dout, const struct impr_effect *peffect)
-{
-  dio_put_uint8(dout, peffect->type);
-  dio_put_uint8(dout, peffect->range);
-  dio_put_sint16(dout, peffect->amount);
-  dio_put_uint8(dout, peffect->survives);
-  dio_put_uint8(dout, peffect->cond_bldg);
-  dio_put_uint8(dout, peffect->cond_gov);
-  dio_put_uint8(dout, peffect->cond_adv);
-  dio_put_uint8(dout, peffect->cond_eff);
-  dio_put_uint8(dout, peffect->aff_unit);
-  dio_put_uint8(dout, peffect->aff_terr);
-  dio_put_uint16(dout, peffect->aff_spec);
-}
Index: common/dataio.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/dataio.h,v
retrieving revision 1.6
diff -u -r1.6 dataio.h
--- common/dataio.h     2 Jun 2004 19:47:41 -0000       1.6
+++ common/dataio.h     1 Sep 2004 01:53:06 -0000
@@ -17,7 +17,6 @@
 
 struct worklist;
 struct player_diplstate;
-struct impr_effect;
 
 struct data_in {
   const void *src;
@@ -71,7 +70,6 @@
 void dio_get_tech_list(struct data_in *din, int *dest);
 void dio_get_worklist(struct data_in *din, struct worklist *pwl);
 void dio_get_diplstate(struct data_in *din, struct player_diplstate *pds);
-void dio_get_effect(struct data_in *din, struct impr_effect *peffect);
 
 void dio_get_uint8_vec8(struct data_in *din, int **values, int stop_value);
 void dio_get_uint16_vec8(struct data_in *din, int **values, int stop_value);
@@ -100,8 +98,6 @@
 void dio_put_worklist(struct data_out *dout, const struct worklist *pwl);
 void dio_put_diplstate(struct data_out *dout,
                       const struct player_diplstate *pds);
-void dio_put_effect(struct data_out *dout,
-                   const struct impr_effect *peffect);
 
 void dio_put_uint8_vec8(struct data_out *dout, int *values, int stop_value);
 void dio_put_uint16_vec8(struct data_out *dout, int *values, int stop_value);
Index: common/effects.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.c,v
retrieving revision 1.6
diff -u -r1.6 effects.c
--- common/effects.c    28 Aug 2004 19:15:39 -0000      1.6
+++ common/effects.c    1 Sep 2004 01:53:06 -0000
@@ -1,5 +1,5 @@
 /********************************************************************** 
- Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+ Freeciv - Copyright (C) 2004 - The Freeciv Team
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
@@ -15,25 +15,30 @@
 #endif
 
 #include <assert.h>
+#include <ctype.h>
+#include <string.h>
 
+#include "city.h"
 #include "effects.h"
 #include "game.h"
 #include "government.h"
 #include "improvement.h"
+#include "log.h"
 #include "map.h"
 #include "mem.h"
+#include "packets.h"
+#include "player.h"
 #include "support.h"
 #include "tech.h"
 #include "shared.h" /* ARRAY_SIZE */
-
-
+ 
 /* Names of effect ranges.
  * (These must correspond to enum effect_range_id in effects.h.)
  * do not change these unless you know what you're doing! */
 static const char *effect_range_names[] = {
   "Local",
   "City",
-  "Island",
+  "Continent",
   "Player",
   "World"
 };
@@ -41,20 +46,14 @@
 /* Names of effect types.
  * (These must correspond to enum effect_type_id in effects.h.) */
 static const char *effect_type_names[] = {
-  "Adv_Parasite",
+  "Tech_Parasite",
   "Airlift",
   "Any_Government",
-  "Barb_Attack",
-  "Barb_Defend",
-  "Building_Cost",
-  "Building_Cost_Pct",
   "Capital_City",
-  "Capital_Exists",
-  "Corrupt_Adj",
   "Corrupt_Pct",
+  "Waste_Pct",
   "Enable_Nuke",
   "Enable_Space",
-  "Enemy_Peaceful",
   "Food_Add_Tile",
   "Food_Bonus",
   "Food_Pct",
@@ -62,10 +61,9 @@
   "Food_Per_Tile",
   "Force_Content",
   "Force_Content_Pct",
-  "Give_Imm_Adv",
+  "Give_Imm_Tech",
   "Growth_Food",
   "Have_Embassies",
-  "Improve_Rep",
   "Luxury_Bonus",
   "Luxury_Pct",
   "Make_Content",
@@ -73,7 +71,6 @@
   "Make_Content_Mil_Per",
   "Make_Content_Pct",
   "Make_Happy",
-  "May_Declare_War",
   "No_Anarchy",
   "No_Sink_Deep",
   "Nuke_Proof",
@@ -91,13 +88,11 @@
   "Prod_To_Gold",
   "Reveal_Cities",
   "Reveal_Map",
-  "Revolt_Dist_Adj",
-  "Revolt_Dist_Pct",
+  "Incite_Dist_Adj",
+  "Incite_Dist_Pct",
   "Science_Bonus",
   "Science_Pct",
   "Size_Unlimit",
-  "Slow_Nuke_Winter",
-  "Slow_Global_Warm",
   "Space_Part",
   "Spy_Resistant",
   "Tax_Bonus",
@@ -107,24 +102,34 @@
   "Trade_Pct",
   "Trade_Inc_Tile",
   "Trade_Per_Tile",
-  "Trade_Route_Pct",
-  "Unit_Attack",
-  "Unit_Attack_Firepower",
-  "Unit_Cost",
-  "Unit_Cost_Pct",
-  "Unit_Defend",
-  "Unit_Defend_Firepower",
-  "Unit_Move",
+  "Sea_Move",
   "Unit_No_Lose_Pop",
   "Unit_Recover",
-  "Unit_Repair",
-  "Unit_Vet_Combat",
-  "Unit_Veteran",
   "Upgrade_One_Step",
   "Upgrade_One_Leap",
   "Upgrade_All_Step",
   "Upgrade_All_Leap",
-  "Upkeep_Free"
+  "Upkeep_Free",
+  "No_Unhappy",
+  "Land_Veteran",
+  "Sea_Veteran",
+  "Air_Veteran",
+  "Land_Vet_Combat",
+  "Sea_Vet_Combat",
+  "Air_Vet_Combat",
+  "Land_Regen",
+  "Sea_Regen",
+  "Air_Regen",
+  "Land_Defend",
+  "Sea_Defend",
+  "Air_Defend",
+  "Missile_Defend",
+  "Size_Adj",
+  "No_Upkeep",
+  "SS_Structural",
+  "SS_Component",
+  "SS_Module",
+  "No_Incite"
 };
 
 /**************************************************************************
@@ -194,44 +199,877 @@
 }
 
 /**************************************************************************
-  Return TRUE iff the two effects are equal.
+  The code creates a ruleset cache on ruleset load. This constant cache
+  is used to speed up effects queries. There is no further memory
+  allocation or de-allocation by any of the code after cache creation.
+
+  Since the cache is constant, the server only needs to send effects data to
+  the client upon connect. It also means that an AI can do fast searches in
+  the effects space by trying the possible combinations of addition or
+  removal of buildings with the effects it cares about, like is done in the
+  existing code.
+
+
+  To know how much a target is being affected, simply use the convenience
+  functions:
+
+  * get_player_bonus
+  * get_city_bonus
+  * get_city_tile_bonus
+  * get_building_bonus
+
+  These functions require as arguments the target and the effect type to be
+  queried.
+
+  Source buildings are unique and at a well known place in the
+  data structures. This allows lots of optimizations in the code.
+
+
+  === Future extensions:
+  The uniqueness aspect of a source is not as important as it being in a
+  well known place. Since a wonder is in a well known place, i.e.
+  game.global_wonders[], it is easy to find out if something is affected by
+  it or not.
+
+  This could easily be extended by generalizing it to these arrays:
+    game.impr[], pplayer->impr[], pisland->impr[], pcity->impr[].
+
+  Which would store the number of buildings of that type present by game,
+  player, island or city. A similar, game wide only array would be kept
+  for surviving effects.
+
+  This should enable basic support for small wonders and satellites.
+
+  Since this means one always knows where to look for a source, we
+  can have very fast queries on effects that will scale well with complex
+  effects.
 **************************************************************************/
-bool are_effects_equal(const struct impr_effect *const peff1,
-                      const struct impr_effect *const peff2)
+
+static const char *req_type_names[] = {
+  "None",
+  "Tech",
+  "Gov",
+  "Building",
+  "Special",
+  "Terrain"
+};
+
+struct eff_group_element {
+  Impr_Type_id improvement;
+  enum effect_range range;
+  bool survives;
+};
+
+#define SPECLIST_TAG eff_group_element
+#define SPECLIST_TYPE struct eff_group_element
+#include "speclist.h"
+
+#define eff_group_element_list_iterate(list, elt) \
+TYPED_LIST_ITERATE(struct eff_group_element, list, elt)
+#define eff_group_element_list_iterate_end  LIST_ITERATE_END
+
+struct eff_group {
+  char *name;
+  int id;
+  struct eff_group_element_list elements;
+};
+
+#define SPECLIST_TAG eff_group
+#define SPECLIST_TYPE struct eff_group
+#include "speclist.h"
+
+#define eff_group_list_iterate(list, pgroup) \
+TYPED_LIST_ITERATE(struct eff_group, list, pgroup)
+#define eff_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 {
+    struct building_vector buildings;
+    struct eff_list buckets[B_LAST];
+  } effs[EFT_LAST];
+
+  struct {
+    struct eft_vector types;
+  } buildings[B_LAST];
+
+} ruleset_cache;
+
+static struct eff_group_list groups;
+static int groups_id;
+
+
+/**************************************************************************
+  Wrappers for access to ruleset cache data.
+**************************************************************************/
+
+/**************************************************************************
+  Get a vector of buildings which grant the effect type.
+**************************************************************************/
+static inline struct building_vector *get_buildings_with_effect(
+    enum effect_type eff)
 {
-#define T(name) if(peff1->name!=peff2->name) return FALSE;
-  T(type);
-  T(range);
-  T(amount);
-  T(survives);
-  T(cond_bldg);
-  T(cond_gov);
-  T(cond_adv);
-  T(cond_eff);
-  T(aff_unit);
-  T(aff_terr);
-  T(aff_spec);
-  return TRUE;
+  return &ruleset_cache.effs[eff].buildings;
 }
 
 /**************************************************************************
-  Returns the effect bonus the currently-in-construction-item will provide.
-
-  Note this is not called get_current_production_bonus because that would
-  be confused with EFT_PROD_BONUS.
-
-  TODO:
-    1.  This function does not access the effect data directly; instead
-        it just associates the effect with a building.
-    2.  Only a few effects are supported.
+  Get a list of effects of a type granted by a building.
 **************************************************************************/
-int get_current_construction_bonus(const struct city *pcity,
-                                  enum effect_type effect)
+inline struct eff_list *get_building_effects(Impr_Type_id id,
+    enum effect_type eff)
 {
-  if (effect == EFT_PROD_TO_GOLD) {
-    return (!pcity->is_building_unit 
-           && pcity->currently_building == B_CAPITAL) ? 1 : 0;
+  return &ruleset_cache.effs[eff].buckets[id];
+}
+
+/**************************************************************************
+  Get a vector of effects types granted by a building.
+**************************************************************************/
+struct eft_vector *get_building_effect_types(Impr_Type_id id)
+{
+  return &ruleset_cache.buildings[id].types;
+}
+
+
+/**************************************************************************
+  Get requirements type from string.
+**************************************************************************/
+enum req_type req_type_from_str(const char *str)
+{
+  enum req_type id;
+
+  for (id = 1; id < ARRAY_SIZE(req_type_names); id++) {
+    if (0 == mystrcasecmp(req_type_names[id], str)) {
+      return id;
+    }
+  }
+
+  return REQ_LAST;
+}
+
+/**************************************************************************
+  Create a new effects group.
+**************************************************************************/
+struct eff_group *eff_group_new(const char *name)
+{
+  struct eff_group *group;
+
+  group = fc_malloc(sizeof(*group));
+  group->name = mystrdup(name);
+  group->id = groups_id++;
+  eff_group_element_list_init(&group->elements);
+
+  eff_group_list_insert_back(&groups, group);
+  return group;
+}
+
+/**************************************************************************
+  Add a new building to an existing effects group.
+**************************************************************************/
+void eff_group_add(struct eff_group *group, Impr_Type_id id,
+              enum effect_range range, bool survives)
+{
+  struct eff_group_element *elt;
+
+  elt = fc_malloc(sizeof(*elt));
+  elt->improvement = id;
+  elt->range = range;
+  elt->survives = survives;
+
+  eff_group_element_list_insert_back(&group->elements, elt);
+}
+
+/**************************************************************************
+  Find the id of an effects group by name.
+**************************************************************************/
+int find_eff_group(const char *name)
+{
+  int i = 0;
+
+  eff_group_list_iterate(groups, pgroup) {
+    if (0 == strcasecmp(pgroup->name, name)) {
+      return i;
+    }
+    i++;
+  } eff_group_list_iterate_end;
+
+  return -1;
+}
+
+/**************************************************************************
+  Initialize ruleset cache.
+**************************************************************************/
+void ruleset_cache_init(void)
+{
+  int i, j;
+
+  assert(ARRAY_SIZE(req_type_names) == REQ_LAST);
+
+  eff_group_list_init(&groups);
+  groups_id = 0;
+
+  for (i = 0; i < ARRAY_SIZE(ruleset_cache.buildings); i++) {
+    eft_vector_init(get_building_effect_types(i));
+  }
+
+  for (i = 0; i < ARRAY_SIZE(ruleset_cache.effs); i++) {
+    building_vector_init(get_buildings_with_effect(i));
+
+    for (j = 0; j < ARRAY_SIZE(ruleset_cache.effs[i].buckets); j++) {
+      eff_list_init(get_building_effects(j, i));
+    }
+  }
+}
+
+/**************************************************************************
+  Parse effect requirement.
+**************************************************************************/
+int parse_req(Impr_Type_id id, enum req_type type, const char *arg)
+{
+  bool problem;
+  int data;
+  struct government *pgov;
+
+  switch (type) {
+    case REQ_NONE:
+      problem = FALSE;
+      data = 0;
+      break;
+    case REQ_TECH:
+      problem = (A_LAST == (data = find_tech_by_name(arg)));
+      break;
+    case REQ_GOV:
+       if (!(pgov = find_government_by_name(arg))) {
+         problem = TRUE;
+       } else {
+         problem = FALSE;
+         data = pgov->index;
+       }
+      break;
+    case REQ_BUILDING:
+      problem = (B_LAST == (data = find_improvement_by_name(arg)));
+      break;
+    case REQ_SPECIAL:
+      problem = (S_NO_SPECIAL == (data = get_special_by_name(arg)));
+      break;
+    case REQ_TERRAIN:
+      problem = (T_UNKNOWN == (data = get_terrain_by_name(arg)));
+      break;
+    default:
+      freelog(LOG_ERROR, "for %s: unimplemented requirement type '%d'",
+             get_improvement_name(id), type);
+      return -1;
+  }
+
+  if (problem) {
+    freelog(LOG_ERROR, "for %s: bad requirement data '%s'",
+           get_improvement_name(id), arg);
+    return -1;
+  } else {
+    return data;
+  }
+}
+
+/**************************************************************************
+  Add effect to ruleset cache.
+**************************************************************************/
+void ruleset_cache_add(Impr_Type_id id, enum effect_type eff,
+                      enum effect_range range, bool survives,
+                      int value,
+                      enum req_type req, int arg, int group)
+{
+  struct effect *peff;
+
+  peff = fc_malloc(sizeof(*peff));
+
+  peff->range = range;
+  peff->survives = survives;
+  peff->value = value;
+
+  peff->req.type = req;
+
+  switch (req) {
+    case REQ_NONE:
+      break;
+    case REQ_TECH:
+       peff->req.value.tech = arg;
+      break;
+    case REQ_GOV:
+       peff->req.value.gov = arg;
+      break;
+    case REQ_BUILDING:
+       peff->req.value.building = arg;
+      break;
+    case REQ_SPECIAL:
+       peff->req.value.special = arg;
+      break;
+    case REQ_TERRAIN:
+       peff->req.value.terrain = arg;
+      break;
+    case REQ_LAST:
+      assert(0);
+      break;
+  }
+
+  eff_list_insert_back(get_building_effects(id, eff), peff);
+
+  if (group >= 0) {
+    peff->group = eff_group_list_get(&groups, group);
+  } else {
+    peff->group = NULL;
+  }
+
+  /* Add improvement type to the effect's buildings vector. */
+  {
+    struct building_vector *vec;
+    Impr_Type_id *pbldg;
+
+    vec = get_buildings_with_effect(eff);
+
+    if (!(pbldg = building_vector_get(vec, -1)) || *pbldg != id) {
+      building_vector_append(vec, &id);
+    }
+  }
+
+  /* Add effect type to the building's effect types vector. */
+  {
+    struct eft_vector *vec;
+    bool exists = FALSE;
+
+    vec = get_building_effect_types(id);
+
+    eft_vector_iterate(vec, ptype) {
+      if (*ptype == eff) {
+       exists = TRUE;
+       break;
+      }
+    } eft_vector_iterate_end;
+
+    if (!exists) {
+      eft_vector_append(vec, &eff);
+    }
+  }
+}
+
+/**************************************************************************
+  Send the ruleset cache groups data.
+**************************************************************************/
+static void send_ruleset_cache_groups(struct conn_list *dest)
+{
+  struct packet_ruleset_cache_group packet;
+  int i;
+
+  eff_group_list_iterate(groups, pgroup) {
+    sz_strlcpy(packet.name, pgroup->name);
+
+    packet.num_elements = eff_group_element_list_size(&pgroup->elements);
+    for (i = 0; i < packet.num_elements; i++) {
+      struct eff_group_element *elt;
+
+      elt = eff_group_element_list_get(&pgroup->elements, i);
+      packet.improvements[i] = elt->improvement;
+      packet.ranges[i] = elt->range;
+      packet.survives[i] = elt->survives;
+    }
+
+    lsend_packet_ruleset_cache_group(dest, &packet);
+  } eff_group_list_iterate_end;
+}
+
+/**************************************************************************
+  Send the ruleset cache effects data.
+**************************************************************************/
+static void send_ruleset_cache_effects(struct conn_list *dest)
+{
+  struct packet_ruleset_cache_effect packet;
+  enum effect_type eff;
+
+  for (eff = 0; eff < EFT_LAST; eff++) {
+    packet.eff = eff;
+
+    building_vector_iterate(get_buildings_with_effect(eff), id) {
+      packet.id = *id;
+
+      eff_list_iterate(*get_building_effects(*id, eff), peff) {
+       packet.range = peff->range;
+       packet.survives = peff->survives;
+        packet.value = peff->value;
+       packet.req = peff->req.type;
+
+       if (peff->group) {
+         packet.group = peff->group->id;
+       } else {
+         packet.group = -1;
+       }
+
+       switch (packet.req) {
+         case REQ_NONE:
+           packet.arg = 0;
+           break;
+         case REQ_TECH:
+           packet.arg = peff->req.value.tech;
+           break;
+         case REQ_GOV:
+           packet.arg = peff->req.value.gov;
+           break;
+         case REQ_BUILDING:
+           packet.arg = peff->req.value.building;
+           break;
+         case REQ_SPECIAL:
+           packet.arg = peff->req.value.special;
+           break;
+         case REQ_TERRAIN:
+           packet.arg = peff->req.value.terrain;
+           break;
+         case REQ_LAST:
+           assert(0);
+           break;
+       }
+
+       lsend_packet_ruleset_cache_effect(dest, &packet);
+      } eff_list_iterate_end;
+    } building_vector_iterate_end;
+  }
+}
+
+/**************************************************************************
+  Send the ruleset cache data over the network.
+**************************************************************************/
+void send_ruleset_cache(struct conn_list *dest)
+{
+  send_ruleset_cache_groups(dest);
+  send_ruleset_cache_effects(dest);
+}
+
+/**************************************************************************
+  Returns a buildable, non-obsolete building that can provide the effect.
+**************************************************************************/
+Impr_Type_id find_source_building(struct player *plr, enum effect_type eff)
+{
+  /* FIXME: this just returns the first building. it should return the best
+   * building instead. */
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    if (can_player_build_improvement(plr, *pbldg)
+       && !improvement_obsolete(plr, *pbldg)
+       && !is_wonder(*pbldg)) {
+      return *pbldg;
+    }
+  } building_vector_iterate_end;
+  return B_LAST;
+}
+
+/**************************************************************************
+  Get a building which grants this effect. Returns B_LAST if there is none.
+**************************************************************************/
+Impr_Type_id get_building_for_effect(enum effect_type eff)
+{
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    return *pbldg;
+  } building_vector_iterate_end;
+  return B_LAST;
+}
+
+/**************************************************************************
+  Can the building grant this effect?
+**************************************************************************/
+bool building_has_effect(Impr_Type_id id, enum effect_type eff)
+{
+  return (eff_list_size(get_building_effects(id, eff)) > 0);
+}
+
+/**************************************************************************
+  Returns the number of surviving world buildings.
+**************************************************************************/
+static int num_surviving_buildings(Impr_Type_id id)
+{
+  if (is_wonder(id) && game.global_wonders[id] != 0) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/**************************************************************************
+  Returns the number of buildings of a certain type in the world.
+**************************************************************************/
+static int num_world_buildings(Impr_Type_id id)
+{
+  if (is_wonder(id) && find_city_by_id(game.global_wonders[id])) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/**************************************************************************
+  Returns the number of buildings of a certain type owned by plr.
+**************************************************************************/
+static int num_player_buildings(const struct player *plr, Impr_Type_id id)
+{
+  if (is_wonder(id) && player_find_city_by_id(plr, game.global_wonders[id])) {
+    return 1;
+  } else { 
+    return 0;
+  }
+}
+
+/**************************************************************************
+  Returns the number buildings of a certain type in a continent.
+**************************************************************************/
+static int num_continent_buildings(const struct player *plr, int continent,
+                                  Impr_Type_id id)
+{
+  if (is_wonder(id)) {
+    struct city *tmp;
+
+    tmp = player_find_city_by_id(plr, game.global_wonders[id]);
+    if (tmp && map_get_continent(tmp->x, tmp->y) == continent) {
+      return 1;
+    }
+  }  
+  return 0;
+}
+
+/**************************************************************************
+  Returns the number of buildings of a certain type in a city.
+**************************************************************************/
+static int num_city_buildings(const struct city *pcity, Impr_Type_id id)
+{
+  return (city_got_building(pcity, id) ? 1 : 0);
+}
+
+/**************************************************************************
+  Is this target possible for the range involved?
+  e.g. you can only affect a player target with something of at least
+  player range.
+**************************************************************************/
+static inline bool is_target_possible(enum target_type target,
+                                    enum effect_range range)
+{
+  switch (target) {
+  case TARGET_PLAYER:
+    return (range >= EFR_PLAYER);
+  case TARGET_CITY:
+    return (range >= EFR_CITY);
+  case TARGET_BUILDING:
+    return (range >= EFR_LOCAL);
   }
   assert(0);
+  return FALSE;
+}
+
+/**************************************************************************
+  How many targets (player, city, building) are in range of the source
+  building?
+**************************************************************************/
+static int targets_in_range(enum target_type target,
+                           const struct player *plr,
+                           const struct city *pcity,
+                           Impr_Type_id building,
+                           enum effect_range range, bool survives,
+                           Impr_Type_id source)
+{
+  if (!is_target_possible(target, range)) {
+    return 0;
+  }
+
+  if (improvement_obsolete(plr, source)) {
+    return 0;
+  }
+
+  if (survives) {
+    if (range == EFR_WORLD) {
+      return num_surviving_buildings(source);
+    } else {
+      return 0;
+    }
+  }
+
+  switch (range) {
+    case EFR_WORLD:
+      return num_world_buildings(source);
+    case EFR_PLAYER:
+      return num_player_buildings(plr, source);
+    case EFR_CONTINENT:
+      {
+       int continent;
+
+       continent = map_get_continent(pcity->x, pcity->y);
+
+       return num_continent_buildings(plr, continent, source);
+      }
+    case EFR_CITY:
+      return num_city_buildings(pcity, source);
+    case EFR_LOCAL:
+      if (building == source) {
+       return num_city_buildings(pcity, source);
+      } else {
+       return 0;
+      }
+    default:
+      return 0;
+  }
+}
+
+/**************************************************************************
+  Is the effect from the source building redundant
+  (i.e. are its effects replaced by other sources in the group)?
+**************************************************************************/
+static bool eff_redundant(enum target_type target,
+                         const struct player *plr,
+                         const struct city *pcity,
+                         Impr_Type_id id,
+                         Impr_Type_id source,
+                         const struct effect *eff)
+{
+  if (eff->group) {
+    /* got more than one building in the same equiv group?
+     * first in the group that exists wins. */
+    eff_group_element_list_iterate(eff->group->elements, elt) {
+      if (elt->improvement == source) {
+       return FALSE;
+      } else {
+       if (targets_in_range(target, plr, pcity, id, elt->range, elt->survives,
+                           elt->improvement) > 0) {
+         return TRUE;
+       }
+      }
+    } eff_group_element_list_iterate_end;
+  }
+  return FALSE;
+}
+
+/**************************************************************************
+  Are the effect requirements active?
+**************************************************************************/
+static bool eff_reqs_active(enum target_type target,
+                           const struct player *plr,
+                           const struct city *pcity,
+                           Impr_Type_id id,
+                           const struct tile *ptile,
+                           Impr_Type_id source,
+                           const struct effect *eff)
+{
+  bool active = FALSE;
+
+  switch (eff->req.type) {
+    case REQ_NONE:
+      active = TRUE;
+      break;
+    case REQ_TECH:
+      active = plr && player_knows_tech(plr, eff->req.value.tech);
+      break;
+    case REQ_GOV:
+      active = plr && (plr->government == eff->req.value.gov);
+      break;
+    case REQ_BUILDING:
+      active = (targets_in_range(target, plr, pcity, id, EFR_CITY,
+                                FALSE, eff->req.value.building) > 0);
+      break;
+    case REQ_SPECIAL:
+      active = ptile && tile_has_special(ptile, eff->req.value.special);
+      break;
+    case REQ_TERRAIN:
+      active = ptile && (ptile->terrain == eff->req.value.terrain);
+      break;
+    case REQ_LAST:
+      assert(0);
+      break;
+  }
+
+  return active;
+}
+
+/**************************************************************************
+  Can the effect from the source building be active at a certain target
+  (player, city or building)?
+  Don't do range checks for the actual source being tested, only for deps.
+**************************************************************************/
+bool eff_eventually_active(enum target_type target,
+                          const struct player *plr,
+                          const struct city *pcity,
+                          Impr_Type_id id,
+                          const struct tile *ptile,
+                          Impr_Type_id source,
+                          const struct effect *eff)
+{
+  if (eff_redundant(target, plr, pcity, id, source, eff)) {
+    return FALSE;
+  }
+  return (eff_reqs_active(target, plr, pcity, id, ptile, source, eff));
+}
+
+/**************************************************************************
+  Is the effect from the source building active at a certain target (player,
+  city or building)?
+**************************************************************************/
+static inline bool eff_active(enum target_type target,
+                             const struct player *plr,
+                             const struct city *pcity,
+                             Impr_Type_id id,
+                             const struct tile *ptile,
+                             Impr_Type_id source,
+                             const struct effect *eff)
+{
+  if (targets_in_range(target, plr, pcity, id, eff->range, eff->survives,
+                     source) == 0) {
+    return FALSE;
+  }
+  return eff_eventually_active(target, plr, pcity, id, ptile, source, eff);
+}
+
+/**************************************************************************
+  Returns TRUE if a building is replaced. To be replaced, all building
+  equivs must be disabled.
+**************************************************************************/
+bool building_replaced(const struct city *pcity, Impr_Type_id id)
+{
+  bool equivs_present = FALSE;
+
+  eft_vector_iterate(get_building_effect_types(id), ptype) {
+    eff_list_iterate(*get_building_effects(id, *ptype), peff) {
+      if (!eff_redundant(TARGET_BUILDING, city_owner(pcity), pcity, id,
+                        id, peff)) {
+       return FALSE;
+      }
+      if (peff->group) {
+       equivs_present = TRUE;
+      }
+    } eff_list_iterate_end;
+  } eft_vector_iterate_end;
+  return equivs_present;
+}
+
+/**************************************************************************
+  Get the total value of one source building's effect type.  This is 
+  necessary since one building may have multiple effects of one type.
+**************************************************************************/
+static inline int get_effect_value(enum target_type target,
+                                  const struct player *plr,
+                                  const struct city *pcity,
+                                  Impr_Type_id id,
+                                  const struct tile *ptile,
+                                  Impr_Type_id source, enum effect_type eff)
+{
+  int value = 0;
+
+  eff_list_iterate(*get_building_effects(source, eff), peff) {
+    if (eff_active(target, plr, pcity, id, ptile, source, peff)) {
+      value += peff->value;
+    }
+  } eff_list_iterate_end;
+
+  return value;
+}
+
+/**************************************************************************
+  Returns the effect bonus for a player.
+**************************************************************************/
+int get_player_bonus(const struct player *plr, enum effect_type eff)
+{
+  int bonus = 0;
+
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    bonus += get_effect_value(TARGET_PLAYER, plr, NULL, B_LAST, NULL,
+                             *pbldg, eff);
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+  Returns the effect bonus at a city.
+**************************************************************************/
+int get_city_bonus(const struct city *pcity, enum effect_type eff)
+{
+  int bonus = 0;
+  struct player *plr = city_owner(pcity);
+
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    bonus += get_effect_value(TARGET_CITY, plr, pcity, B_LAST, NULL,
+                             *pbldg, eff);
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+  Returns the effect bonus at a city tile.
+**************************************************************************/
+int get_city_tile_bonus(const struct city *pcity, const struct tile *ptile,
+                       enum effect_type eff)
+{
+  int bonus = 0;
+  struct player *plr = city_owner(pcity);
+ 
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    bonus += get_effect_value(TARGET_CITY, plr, pcity, B_LAST, ptile,
+                             *pbldg, eff);
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+  Returns the effect bonus at a building.
+**************************************************************************/
+int get_building_bonus(const struct city *pcity, Impr_Type_id id,
+                      enum effect_type eff)
+{
+  int bonus = 0;
+  struct player *plr = city_owner(pcity);
+
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    bonus += get_effect_value(TARGET_BUILDING, plr, pcity, id, NULL,
+                             *pbldg, eff);
+  } building_vector_iterate_end;
+
+  return bonus;
+}
+
+/**************************************************************************
+  Returns the effect sources of this type currently active at the city.
+**************************************************************************/
+struct building_vector get_city_bonus_sources(const struct city *pcity,
+                                             enum effect_type eff)
+{
+  struct player *plr = city_owner(pcity);
+  struct building_vector res;
+
+  building_vector_init(&res);
+
+  building_vector_iterate(get_buildings_with_effect(eff), pbldg) {
+    if (get_effect_value(TARGET_CITY, plr, pcity, B_LAST, NULL, *pbldg, eff)) {
+      building_vector_append(&res, pbldg);
+    }
+  } building_vector_iterate_end;
+
+  return res;
+}
+
+/**************************************************************************
+  Returns the effect bonus the currently in construction item will provide.
+**************************************************************************/
+int get_current_construction_bonus(const struct city *pcity,
+                                  enum effect_type eff)
+{
+  if (!pcity->is_building_unit) {
+    Impr_Type_id id;
+    int power = 0;
+
+    id = pcity->currently_building;
+
+    eff_list_iterate(*get_building_effects(id, eff), peff) {
+      if (eff_eventually_active(TARGET_BUILDING, city_owner(pcity), pcity, id,
+         NULL, id, peff)) {
+       power += peff->value;
+      }
+    } eff_list_iterate_end;
+
+    return power;
+  }
+
   return 0;
 }
Index: common/effects.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/effects.h,v
retrieving revision 1.4
diff -u -r1.4 effects.h
--- common/effects.h    28 Aug 2004 19:15:39 -0000      1.4
+++ common/effects.h    1 Sep 2004 01:53:06 -0000
@@ -13,8 +13,6 @@
 #ifndef FC__EFFECTS_H
 #define FC__EFFECTS_H
 
-struct impr_effect;
-
 #include "shared.h"            /* bool */
 
 #include "fc_types.h"
@@ -25,7 +23,7 @@
 enum effect_range {
   EFR_LOCAL,
   EFR_CITY,
-  EFR_ISLAND,
+  EFR_CONTINENT,
   EFR_PLAYER,
   EFR_WORLD,
   EFR_LAST   /* keep this last */
@@ -34,20 +32,14 @@
 /* Type of effects. (Used in effect.type field)
  * These must correspond to effect_type_names[] in effects.c. */
 enum effect_type {
-  EFT_ADV_PARASITE,
+  EFT_TECH_PARASITE,
   EFT_AIRLIFT,
   EFT_ANY_GOVERNMENT,
-  EFT_BARB_ATTACK,
-  EFT_BARB_DEFEND,
-  EFT_BUILDING_COST,
-  EFT_BUILDING_COST_PCT,
   EFT_CAPITAL_CITY,
-  EFT_CAPITAL_EXISTS,
-  EFT_CORRUPT_ADJ,
   EFT_CORRUPT_PCT,
+  EFT_WASTE_PCT,
   EFT_ENABLE_NUKE,
   EFT_ENABLE_SPACE,
-  EFT_ENEMY_PEACEFUL,
   EFT_FOOD_ADD_TILE,
   EFT_FOOD_BONUS,
   EFT_FOOD_PCT,
@@ -55,10 +47,9 @@
   EFT_FOOD_PER_TILE,
   EFT_FORCE_CONTENT,
   EFT_FORCE_CONTENT_PCT,
-  EFT_GIVE_IMM_ADV,
+  EFT_GIVE_IMM_TECH,
   EFT_GROWTH_FOOD,
   EFT_HAVE_EMBASSIES,
-  EFT_IMPROVE_REP,
   EFT_LUXURY_BONUS,
   EFT_LUXURY_PCT,
   EFT_MAKE_CONTENT,
@@ -66,7 +57,6 @@
   EFT_MAKE_CONTENT_MIL_PER,
   EFT_MAKE_CONTENT_PCT,
   EFT_MAKE_HAPPY,
-  EFT_MAY_DECLARE_WAR,
   EFT_NO_ANARCHY,
   EFT_NO_SINK_DEEP,
   EFT_NUKE_PROOF,
@@ -84,13 +74,11 @@
   EFT_PROD_TO_GOLD,
   EFT_REVEAL_CITIES,
   EFT_REVEAL_MAP,
-  EFT_REVOLT_DIST_ADJ,
-  EFT_REVOLT_DIST_Pct,
+  EFT_INCITE_DIST_ADJ,
+  EFT_INCITE_DIST_PCT,
   EFT_SCIENCE_BONUS,
   EFT_SCIENCE_PCT,
   EFT_SIZE_UNLIMIT,
-  EFT_SLOW_NUKE_WINTER,
-  EFT_SLOW_GLOBAL_WARM,
   EFT_SPACE_PART,
   EFT_SPY_RESISTANT,
   EFT_TAX_BONUS,
@@ -100,39 +88,168 @@
   EFT_TRADE_PCT,
   EFT_TRADE_INC_TILE,
   EFT_TRADE_PER_TILE,
-  EFT_TRADE_ROUTE_PCT,
-  EFT_UNIT_ATTACK,
-  EFT_UNIT_ATTACK_FIREPOWER,
-  EFT_UNIT_COST,
-  EFT_UNIT_COST_PCT,
-  EFT_UNIT_DEFEND,
-  EFT_UNIT_DEFEND_FIREPOWER,
-  EFT_UNIT_MOVE,
+  EFT_SEA_MOVE,
   EFT_UNIT_NO_LOSE_POP,
   EFT_UNIT_RECOVER,
-  EFT_UNIT_REPAIR,
-  EFT_UNIT_VET_COMBAT,
-  EFT_UNIT_VETERAN,
   EFT_UPGRADE_ONE_STEP,
   EFT_UPGRADE_ONE_LEAP,
   EFT_UPGRADE_ALL_STEP,
   EFT_UPGRADE_ALL_LEAP,
   EFT_UPKEEP_FREE,
+  EFT_NO_UNHAPPY,
+  EFT_LAND_VETERAN,
+  EFT_SEA_VETERAN,
+  EFT_AIR_VETERAN,
+  EFT_LAND_VET_COMBAT,
+  EFT_SEA_VET_COMBAT,
+  EFT_AIR_VET_COMBAT,
+  EFT_LAND_REGEN,
+  EFT_SEA_REGEN,
+  EFT_AIR_REGEN,
+  EFT_LAND_DEFEND,
+  EFT_SEA_DEFEND,
+  EFT_AIR_DEFEND,
+  EFT_MISSILE_DEFEND,
+  EFT_SIZE_ADJ,
+  EFT_NO_UPKEEP,
+  EFT_SS_STRUCTURAL,
+  EFT_SS_COMPONENT,
+  EFT_SS_MODULE,
+  EFT_NO_INCITE,
   EFT_LAST     /* keep this last */
 };
 
-#define EFT_ALL EFT_LAST
-
 /* lookups */
 enum effect_range effect_range_from_str(const char *str);
 const char *effect_range_name(enum effect_range id);
 enum effect_type effect_type_from_str(const char *str);
 const char *effect_type_name(enum effect_type id);
 
-bool are_effects_equal(const struct impr_effect *const peff1,
-                      const struct impr_effect *const peff2);
+/* Typedefs. */
+#define eff_list_iterate(list, peff) \
+TYPED_LIST_ITERATE(struct effect, list, peff)
+#define eff_list_iterate_end  LIST_ITERATE_END
+
+#define SPECVEC_TAG building
+#define SPECVEC_TYPE Impr_Type_id
+#include "specvec.h"
+
+#define building_vector_iterate(vector, pbldg) \
+TYPED_VECTOR_ITERATE(Impr_Type_id, vector, pbldg)
+#define building_vector_iterate_end  VECTOR_ITERATE_END
+
+#define SPECVEC_TAG eft
+#define SPECVEC_TYPE enum effect_type
+#include "specvec.h"
+
+#define eft_vector_iterate(vector, ptype) \
+TYPED_VECTOR_ITERATE(enum effect_type, vector, ptype)
+#define eft_vector_iterate_end  VECTOR_ITERATE_END
+
+/* Effect requirement type. */
+enum req_type {
+  REQ_NONE,
+  REQ_TECH,
+  REQ_GOV,
+  REQ_BUILDING,
+  REQ_SPECIAL,
+  REQ_TERRAIN,
+  REQ_LAST
+};
+
+struct eff_group;
+
+struct effect {
+  enum effect_range range;                     /* effect range */
+
+  int value;                                   /* effect modifier value */
+
+  struct eff_group *group;                     /* effect group */
+  bool survives;                               /* does this effect survive? */
+
+  struct {
+    enum req_type type;                                /* requirement type */
+
+    union {
+      Tech_Type_id tech;                       /* requirement tech */
+      int gov;                                 /* requirement government */
+      Impr_Type_id building;                   /* requirement building */
+      enum tile_special_type special;          /* requirement special */
+      enum tile_terrain_type terrain;          /* requirement terrain type */
+    } value;                                   /* requirement value */
+  } req;
+};
+
+#define SPECLIST_TAG eff
+#define SPECLIST_TYPE struct effect
+#include "speclist.h"
+
+struct conn_list;
+
+struct city;
+struct player;
+struct tile;
+
+/* ruleset cache creation and communication functions */
+void ruleset_cache_init(void);
+
+void ruleset_cache_add(Impr_Type_id id, enum effect_type eff,
+    enum effect_range range, bool survives,
+    int value,
+    enum req_type req, int arg, int equiv);
+
+void send_ruleset_cache(struct conn_list *dest);
+
+/* equivalent effect group */
+struct eff_group *eff_group_new(const char *name);
+void eff_group_add(struct eff_group *group, Impr_Type_id id,
+    enum effect_range range, bool survives);
+int find_eff_group(const char *name);
+
+/* name string to value functions */
+enum req_type req_type_from_str(const char *str);
+int parse_req(Impr_Type_id id, enum req_type req, const char *arg);
+
+/* effect presence tests */
+enum target_type {
+  TARGET_PLAYER,
+  TARGET_CITY,
+  TARGET_BUILDING 
+};
+
+bool eff_eventually_active(enum target_type target,
+    const struct player *plr,
+    const struct city *pcity,
+    Impr_Type_id id,
+    const struct tile *ptile,
+    Impr_Type_id source,
+    const struct effect *eff);
+
+bool building_replaced(const struct city *pcity, Impr_Type_id id);
+
+/* functions to know the bonuses a certain effect is granting */
+int get_player_bonus(const struct player *plr, enum effect_type eff);
+
+int get_city_bonus(const struct city *pcity, enum effect_type eff);
+int get_city_tile_bonus(const struct city *city, const struct tile *ptile,
+                       enum effect_type eff);
+int get_building_bonus(const struct city *pcity, Impr_Type_id id,
+                      enum effect_type eff);
+
+/* miscellaneous auxiliary effects functions */
+struct eff_list *get_building_effects(Impr_Type_id id, enum effect_type eff);
+struct eft_vector *get_building_effect_types(Impr_Type_id id);
+
+bool building_has_effect(Impr_Type_id id, enum effect_type eff);
+
+struct building_vector get_city_bonus_sources(const struct city *pcity,
+                                             enum effect_type eff);
 
 int get_current_construction_bonus(const struct city *pcity,
                                   enum effect_type effect);
 
+Impr_Type_id find_source_building(struct player *plr, enum effect_type eff);
+Impr_Type_id get_building_for_effect(enum effect_type eff);
+
 #endif  /* FC__EFFECTS_H */
+
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.183
diff -u -r1.183 game.c
--- common/game.c       21 Jul 2004 16:34:33 -0000      1.183
+++ common/game.c       1 Sep 2004 01:53:07 -0000
@@ -278,6 +278,10 @@
   game.government_when_anarchy = G_MAGIC;   /* flag */
   game.ai_goal_government = G_MAGIC;        /* flag */
 
+  game.default_building = B_LAST;
+  game.palace_building = B_LAST;
+  game.land_defend_building = B_LAST;
+
   sz_strlcpy(game.demography, GAME_DEFAULT_DEMOGRAPHY);
   sz_strlcpy(game.allow_take, GAME_DEFAULT_ALLOW_TAKE);
 
@@ -365,8 +369,7 @@
 ***************************************************************/
 int game_next_year(int year)
 {
-  int spaceshipparts, i;
-  Impr_Type_id parts[] = { B_SCOMP, B_SMODULE, B_SSTRUCTURAL, B_LAST };
+  int spaceshipparts;
 
   if (year == 1) /* hacked it to get rid of year 0 */
     year = 0;
@@ -384,13 +387,14 @@
    * about 1900 AD
    */
 
-  spaceshipparts= 0;
+  spaceshipparts = 0;
   if (game.spacerace) {
-    for(i=0; parts[i] < B_LAST; i++) {
-      int t = improvement_types[parts[i]].tech_req;
-      if (tech_exists(t) && game.global_advances[t] != 0)
+    tech_type_iterate(t) {
+      if (tech_exists(t) && game.global_advances[t] != 0
+          && tech_flag(t, TF_SPACE_PARTS_INC)) {
        spaceshipparts++;
-    }
+      }
+    } tech_type_iterate_end;
   }
 
   if( year >= 1900 || ( spaceshipparts>=3 && year>0 ) )
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.148
diff -u -r1.148 game.h
--- common/game.h       16 Aug 2004 15:42:59 -0000      1.148
+++ common/game.h       1 Sep 2004 01:53:07 -0000
@@ -169,6 +169,10 @@
   char rulesetdir[MAX_LEN_NAME];
   int firepower_factor;                /* See README.rulesets */
 
+  Impr_Type_id default_building;
+  Impr_Type_id palace_building;
+  Impr_Type_id land_defend_building;
+
   struct {
     int cathedral_plus;                /* eg Theology */
     int cathedral_minus;       /* eg Communism */
Index: common/government.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/government.c,v
retrieving revision 1.45
diff -u -r1.45 government.c
--- common/government.c 18 Aug 2004 18:11:05 -0000      1.45
+++ common/government.c 1 Sep 2004 01:53:07 -0000
@@ -237,7 +237,7 @@
     return FALSE;
   } else {
     return (get_invention(pplayer, req) == TECH_KNOWN
-           || player_owns_active_govchange_wonder(pplayer));
+           || get_player_bonus(pplayer, EFT_ANY_GOVERNMENT));
   }
 }
 
Index: common/improvement.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/improvement.c,v
retrieving revision 1.43
diff -u -r1.43 improvement.c
--- common/improvement.c        13 Aug 2004 15:59:12 -0000      1.43
+++ common/improvement.c        1 Sep 2004 01:53:07 -0000
@@ -99,9 +99,6 @@
   free(p->equiv_repl);
   p->equiv_repl = NULL;
 
-  free(p->effect);
-  p->effect = NULL;
-
   free(p->helptext);
   p->helptext = NULL;
 }
@@ -130,8 +127,7 @@
   if (id<0 || id>=B_LAST || id>=game.num_impr_types)
     return FALSE;
 
-  if ((id==B_SCOMP || id==B_SMODULE || id==B_SSTRUCTURAL)
-      && !game.spacerace)
+  if (!game.spacerace && building_has_effect(id, EFT_SPACE_PART))
     return FALSE;
 
   return (improvement_types[id].tech_req!=A_LAST);
@@ -177,7 +173,7 @@
   int cost = 0, missing =
       improvement_types[id].build_cost - shields_in_stock;
 
-  if (id == B_CAPITAL) {
+  if (building_has_effect(id, EFT_PROD_TO_GOLD)) {
     /* Can't buy capitalization. */
     return 0;
   }
@@ -351,15 +347,6 @@
 }
 
 /**************************************************************************
-Barbarians don't get enough knowledges to be counted as normal players.
-**************************************************************************/
-bool is_wonder_useful(Impr_Type_id id)
-{
-  if ((id == B_GREAT) && (get_num_human_and_ai_players () < 3)) return FALSE;
-  return TRUE;
-}
-
-/**************************************************************************
  Clears a list of improvements - sets them all to I_NONE
 **************************************************************************/
 void improvement_status_init(Impr_Status * improvements, size_t elements)
@@ -376,77 +363,88 @@
 }
 
 /**************************************************************************
-  Whether player could build this improvement, assuming they had
-  the tech req, and assuming a city with the right pre-reqs etc.
+  Whether player can build given improvement somewhere,
+  ignoring whether improvement is obsolete.
 **************************************************************************/
-bool could_player_eventually_build_improvement(struct player *p,
-                                             Impr_Type_id id)
+bool can_player_build_improvement_direct(struct player *p, Impr_Type_id id)
 {
   struct impr_type *impr;
+  bool space_part = FALSE;
 
   /* This also checks if tech req is Never */
-  if (!improvement_exists(id))
+  if (!improvement_exists(id)) {
     return FALSE;
+  }
+
+  if (!player_knows_improvement_tech(p, id)) {
+    return FALSE;
+  }
 
   impr = get_improvement_type(id);
 
-  if (impr->effect) {
-    struct impr_effect *peffect = impr->effect;
-    enum effect_type type;
-
-    /* This if for a spaceship component is asked */
-    while ((type = peffect->type) != EFT_LAST) {
-      if (type == EFT_SPACE_PART) {
-       /* TODO: remove this */
-       if (game.global_wonders[B_APOLLO] == 0)
-         return FALSE;
-        if (p->spaceship.state >= SSHIP_LAUNCHED)
-         return FALSE;
-       if (peffect->amount == 1 && p->spaceship.structurals >= 
NUM_SS_STRUCTURALS)
-         return FALSE;
-       if (peffect->amount == 2 && p->spaceship.components >= 
NUM_SS_COMPONENTS)
-         return FALSE;
-       if (peffect->amount == 3 && p->spaceship.modules >= NUM_SS_MODULES)
-         return FALSE;
-      }
-      peffect++;
+  /* This if for a spaceship component is asked */
+  if (building_has_effect(id, EFT_SS_STRUCTURAL)) {
+    space_part = TRUE;
+    if (p->spaceship.structurals >= NUM_SS_STRUCTURALS) {
+      return FALSE;
+    }
+  }
+  if (building_has_effect(id, EFT_SS_COMPONENT)) {
+    space_part = TRUE;
+    if (p->spaceship.components >= NUM_SS_COMPONENTS) {
+      return FALSE;
+    }
+  }
+  if (building_has_effect(id, EFT_SS_MODULE)) {
+    space_part = TRUE;
+    if (p->spaceship.modules >= NUM_SS_MODULES) {
+      return FALSE;
     }
   }
+  if (space_part &&
+      (!get_player_bonus(p, EFT_ENABLE_SPACE)
+       || p->spaceship.state >= SSHIP_LAUNCHED)) {
+    return FALSE;
+  }
+
   if (is_wonder(id)) {
     /* Can't build wonder if already built */
     if (game.global_wonders[id] != 0) return FALSE;
-  } else {
-    /* Can't build if obsolette */
-    if (improvement_obsolete(p, id)) return FALSE;
   }
+
   return TRUE;
 }
 
 /**************************************************************************
-...
+  Whether player can _eventually_ build given improvement somewhere -- ie,
+  returns 1 if improvement is available with current tech OR will be available
+  with future tech.  returns 0 if improvement is obsolete.
 **************************************************************************/
-static bool could_player_build_improvement(struct player *p, Impr_Type_id id)
+bool can_player_build_improvement(struct player *p, Impr_Type_id id)
 {
-  if (!could_player_eventually_build_improvement(p, id))
+  if (!can_player_build_improvement_direct(p, id)) {
     return FALSE;
-
-  /* Make sure we have the tech /now/.*/
-  if (get_invention(p, improvement_types[id].tech_req) == TECH_KNOWN)
-    return TRUE;
-  return FALSE;
+  }
+  if (improvement_obsolete(p, id)) {
+    return FALSE;
+  }
+  return TRUE;
 }
-  
+
 /**************************************************************************
-  Can a player build this improvement somewhere?  Ignores the fact that 
-  player may not have a city with appropriate prereqs.
+  Whether player can _eventually_ build given improvement somewhere -- ie,
+  returns 1 if improvement is available with current tech OR will be available
+  with future tech.  returns 0 if unit is obsolete.
 **************************************************************************/
-bool can_player_build_improvement(struct player *p, Impr_Type_id id)
+bool can_player_eventually_build_improvement(struct player *p, Impr_Type_id id)
 {
-  if (!improvement_exists(id))
+  if (!improvement_exists(id)) {
     return FALSE;
-  if (!player_knows_improvement_tech(p,id))
+  }
+  if (improvement_obsolete(p, id)) {
     return FALSE;
-  return(could_player_build_improvement(p, id));
+  }
+  return TRUE;
 }
 
 /**************************************************************************
Index: common/improvement.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/improvement.h,v
retrieving revision 1.30
diff -u -r1.30 improvement.h
--- common/improvement.h        31 Aug 2004 04:40:50 -0000      1.30
+++ common/improvement.h        1 Sep 2004 01:53:07 -0000
@@ -14,6 +14,19 @@
 #define FC__IMPROVEMENT_H
 
 /* City Improvements, including Wonders.  (Alternatively "Buildings".) */
+typedef int Impr_Type_id;
+
+/*
+ * Hack to allow code that explicitly checks for Palace or City Walls
+ * to work.
+ */
+extern int B_CAPITAL_CITY, B_LAND_DEFEND;
+
+/* B_LAST is a value which is guaranteed to be larger than all
+ * actual Impr_Type_id values.  It is used as a flag value;
+ * it can also be used for fixed allocations to ensure ability
+ * to hold full number of improvement types.  */
+#define B_LAST MAX_NUM_ITEMS
 
 #include "fc_types.h"
 
@@ -35,38 +48,6 @@
 #define I_REDUNDANT  3   /* Built, but replaced by wonder/other building */
 
 
-/* FIXME: Remove this define when there is per-file need for this enum. */
-#define OLD_IMPR_TYPE_ENUM
-
-/* FIXME: Remove this enum and the ifdef/endif when gen-impr implemented. */
-#ifdef OLD_IMPR_TYPE_ENUM
-enum improvement_type_id {
-  B_AIRPORT=0, B_AQUEDUCT, B_BANK, B_BARRACKS, B_BARRACKS2, B_BARRACKS3, 
-  B_CATHEDRAL, B_CITY, B_COASTAL, B_COLOSSEUM, B_COURTHOUSE,  B_FACTORY, 
-  B_GRANARY, B_HARBOUR, B_HYDRO, B_LIBRARY, B_MARKETPLACE, B_MASS, B_MFG, 
-  B_NUCLEAR, B_OFFSHORE, B_PALACE, B_POLICE, B_PORT, B_POWER,
-  B_RECYCLING, B_RESEARCH, B_SAM, B_SDI, B_SEWER, B_SOLAR, B_SCOMP, 
-  B_SMODULE, B_SSTRUCTURAL, B_STOCK, B_SUPERHIGHWAYS, B_SUPERMARKET, B_TEMPLE,
-  B_UNIVERSITY,  
-  
-  B_APOLLO, B_ASMITHS, B_COLLOSSUS, B_COPERNICUS, B_CURE, B_DARWIN, B_EIFFEL,
-  B_GREAT, B_WALL, B_HANGING, B_HOOVER, B_ISAAC, B_BACH, B_RICHARDS, 
-  B_LEONARDO, B_LIGHTHOUSE, B_MAGELLAN, B_MANHATTEN, B_MARCO, B_MICHELANGELO, 
-  B_ORACLE, B_PYRAMIDS, B_SETI, B_SHAKESPEARE, B_LIBERTY, B_SUNTZU, 
-  B_UNITED, B_WOMENS,
-  B_CAPITAL, B_LAST_ENUM
-};
-typedef enum improvement_type_id Impr_Type_id;
-#else
-typedef int Impr_Type_id;
-#endif
-
-/* B_LAST is a value which is guaranteed to be larger than all
- * actual Impr_Type_id values.  It is used as a flag value;
- * it can also be used for fixed allocations to ensure ability
- * to hold full number of improvement types.  */
-#define B_LAST MAX_NUM_ITEMS
-
 /* Range of equivalence (used in equiv_range fields)
  * These must correspond to impr_range_names[] in improvement.c. */
 enum impr_range {
@@ -78,25 +59,6 @@
   IR_LAST      /* keep this last */
 };
 
-/* An effect conferred by an improvement. */
-struct impr_effect {
-  enum effect_type type;
-  enum effect_range range;
-  int amount;
-  int survives;                           /* 1 = effect survives wonder 
destruction */
-  Impr_Type_id cond_bldg;         /* B_LAST = unconditional */
-  int cond_gov;                           /* game.government_count = 
unconditional */
-  Tech_Type_id cond_adv;          /* A_NONE = unconditional; A_LAST = never */
-  enum effect_type cond_eff;      /* EFT_LAST = unconditional */
-  Unit_Class_id aff_unit;         /* UCL_LAST = all */
-  Terrain_type_id aff_terr; /* T_UNKNOWN = all; T_NONE = none */
-  enum tile_special_type aff_spec; /* S_* bit mask of specials affected */
-};
-
-/* Maximum number of effects per improvement 
- * (this should not be more than the number of bits in the Eff_Status type) */
-#define MAX_EFFECTS 16
-  
 /* Type of improvement. (Read from buildings.ruleset file.) */
 struct impr_type {
   char name[MAX_LEN_NAME];
@@ -111,11 +73,11 @@
   Impr_Type_id *equiv_dupl;            /* list; B_LAST terminated */
   Impr_Type_id *equiv_repl;            /* list; B_LAST terminated */
   Tech_Type_id obsolete_by;            /* A_LAST = never obsolete */
+  Impr_Type_id replaced_by;            /* B_LAST = never replaced */
   bool is_wonder;
   int build_cost;                      /* Use wrappers to access this. */
   int upkeep;
   int sabotage;                /* Base chance of diplomat sabotage succeeding. 
*/
-  struct impr_effect *effect;          /* list; .type==EFT_LAST terminated */
   int variant;                 /* FIXME: remove when gen-impr obsoletes */
   struct Sprite *sprite;               /* icon of the improvement */
   char *helptext;
@@ -150,15 +112,15 @@
 bool improvement_redundant(struct player *pplayer, const struct city *pcity,
                           Impr_Type_id id, bool want_to_build);
 bool wonder_obsolete(Impr_Type_id id);
-bool is_wonder_useful(Impr_Type_id id);
 Impr_Type_id find_improvement_by_name(const char *s);
 Impr_Type_id find_improvement_by_name_orig(const char *s);
 void improvement_status_init(Impr_Status * improvements, size_t elements);
 
 /* player related improvement and unit functions */
-bool could_player_eventually_build_improvement(struct player *p, 
-                                               Impr_Type_id id);
+bool can_player_build_improvement_direct(struct player *p, Impr_Type_id id);
 bool can_player_build_improvement(struct player *p, Impr_Type_id id);
+bool can_player_eventually_build_improvement(struct player *p,
+                                            Impr_Type_id id);
 
 /* city related improvement functions */
 void mark_improvement(struct city *pcity,Impr_Type_id id,Impr_Status status);
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.43
diff -u -r1.43 packets.def
--- common/packets.def  27 Aug 2004 17:36:53 -0000      1.43
+++ common/packets.def  1 Sep 2004 01:53:07 -0000
@@ -157,7 +157,6 @@
 type BIT_STRING                = bit_string(char)
 type WORKLIST          = worklist(struct worklist)
 type TECH_LIST         = tech_list(int)
-type EFFECT            = effect(struct impr_effect)
 
 # typedefs for enums
 type CLAUSE            = uint8(enum clause_type)
@@ -178,6 +177,11 @@
 type ORDERS            = uint8(enum unit_orders)
 type SSET_TYPE         = uint8(enum sset_type)
 
+# typedefs for effects
+type EFF               = uint8(enum effect_type)
+type EFR               = uint8(enum effect_range)
+type REQ               = uint8(enum req_type)
+
 # typedefs for IDs
 type PLAYER            = UINT8
 type CITY              = UINT16
@@ -1142,8 +1146,9 @@
   STRING graphic_str[MAX_LEN_NAME];
   STRING graphic_alt[MAX_LEN_NAME];
   TECH tech_req, obsolete_by;
-  IMPROVEMENT bldg_req;
+  IMPROVEMENT bldg_req, replaced_by;
   BOOL is_wonder;
+  IMPR_RANGE affected_cities;
   IMPR_RANGE equiv_range;
   UINT16 build_cost;
   UINT8 upkeep, sabotage;
@@ -1159,8 +1164,6 @@
   IMPROVEMENT equiv_dupl[255:equiv_dupl_count];
   UINT8 equiv_repl_count;
   IMPROVEMENT equiv_repl[255:equiv_repl_count];
-  UINT8 effect_count;
-  EFFECT effect[255:effect_count];  
 end
 
 PACKET_RULESET_TERRAIN=105;sc,lsend
@@ -1247,6 +1250,8 @@
   BOOL slow_invasions; add-cap(slow_invasions)
 
   STRING team_name[MAX_NUM_TEAMS][MAX_LEN_NAME];
+
+  IMPROVEMENT default_building;
 end
 
 
@@ -1298,3 +1303,26 @@
 
   UINT8 category;                              /* which category this is in */
 end
+
+/************** Effects hash packets **********************/
+
+PACKET_RULESET_CACHE_GROUP=120;sc,lsend
+  STRING name[MAX_LEN_NAME];
+
+  UINT8 num_elements;
+  IMPROVEMENT improvements[255:num_elements];
+  EFR ranges[255:num_elements];
+  BOOL survives[255:num_elements];
+end
+
+PACKET_RULESET_CACHE_EFFECT=121;sc,lsend
+  IMPROVEMENT id;
+  EFF eff;
+  EFR range;
+  BOOL survives;
+  SINT32 value;
+  REQ req;
+  SINT32 arg;
+  SINT32 group;
+end
+
Index: common/packets.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v
retrieving revision 1.162
diff -u -r1.162 packets.h
--- common/packets.h    14 Jan 2004 11:58:12 -0000      1.162
+++ common/packets.h    1 Sep 2004 01:53:07 -0000
@@ -19,7 +19,7 @@
 #include "connection.h"                /* struct connection, MAX_LEN_* */
 #include "diptreaty.h"
 #include "events.h"
-#include "effects.h"
+#include "improvement.h"
 #include "map.h"
 #include "player.h"
 #include "shared.h"            /* MAX_LEN_NAME, MAX_LEN_ADDR */
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.150
diff -u -r1.150 player.c
--- common/player.c     29 Aug 2004 19:03:31 -0000      1.150
+++ common/player.c     1 Sep 2004 01:53:07 -0000
@@ -65,7 +65,7 @@
 {
   return (TEST_BIT(pplayer->embassy, pplayer2->player_no)
           || (pplayer == pplayer2)
-          || (player_owns_active_wonder(pplayer, B_MARCO)
+          || (get_player_bonus(pplayer, EFT_HAVE_EMBASSIES)
               && !is_barbarian(pplayer2)));
 }
 
@@ -370,31 +370,6 @@
 }
 
 /**************************************************************************
- Return 1 if one of the player's cities has the specified wonder,
- and it is not obsolete.
-**************************************************************************/
-bool player_owns_active_wonder(struct player *pplayer,
-                             Impr_Type_id id)
-{
-  return (improvement_exists(id)
-         && is_wonder(id)
-         && (!wonder_obsolete(id))
-         && player_find_city_by_id(pplayer, game.global_wonders[id]));
-}
-
-/**************************************************************************
- ...
-**************************************************************************/
-bool player_owns_active_govchange_wonder(struct player *pplayer)
-{
-  return ( player_owns_active_wonder(pplayer, B_LIBERTY) ||
-          ( (improvement_variant(B_PYRAMIDS)==1) &&
-            player_owns_active_wonder(pplayer, B_PYRAMIDS) ) ||
-          ( (improvement_variant(B_UNITED)==1) &&
-            player_owns_active_wonder(pplayer, B_UNITED) ) );
-}
-
-/**************************************************************************
  Returns the number of techs the player has researched which has this
  flag. Needs to be optimized later (e.g. int tech_flags[TF_LAST] in
  struct player)
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.121
diff -u -r1.121 player.h
--- common/player.h     29 Aug 2004 19:03:31 -0000      1.121
+++ common/player.h     1 Sep 2004 01:53:07 -0000
@@ -218,7 +218,6 @@
   Impr_Status improvements[B_LAST]; /* improvements with equiv_range==Player */
   Impr_Status *island_improv; /* improvements with equiv_range==Island, 
dimensioned to
                                 [map.num_continents][game.num_impr_types] */
-
   struct {
     int length;
     void *data;
@@ -251,9 +250,6 @@
                                    int unit_id);
 
 bool player_in_city_radius(struct player *pplayer, int x, int y);
-bool player_owns_active_wonder(struct player *pplayer,
-                             Impr_Type_id id);
-bool player_owns_active_govchange_wonder(struct player *pplayer);
 bool player_knows_improvement_tech(struct player *pplayer,
                                   Impr_Type_id id);
 bool player_knows_techs_with_flag(struct player *pplayer,
Index: common/tech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.c,v
retrieving revision 1.75
diff -u -r1.75 tech.c
--- common/tech.c       2 Aug 2004 23:19:36 -0000       1.75
+++ common/tech.c       1 Sep 2004 01:53:07 -0000
@@ -41,7 +41,7 @@
   "Bonus_Tech", "Boat_Fast", "Bridge", "Railroad", "Fortress",
   "Watchtower", "Population_Pollution_Inc", "Trade_Revenue_Reduce",
   "Airbase", "Farmland", "Reduce_Trireme_Loss1", "Reduce_Trireme_Loss2", 
-  "Build_Airborne"
+  "Build_Airborne", "Space_Parts_Inc"
 };
 /* Note that these strings must correspond with the enums in tech_flag_id,
    in common/tech.h */
Index: common/tech.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.h,v
retrieving revision 1.46
diff -u -r1.46 tech.h
--- common/tech.h       12 Aug 2004 20:58:59 -0000      1.46
+++ common/tech.h       1 Sep 2004 01:53:07 -0000
@@ -67,6 +67,7 @@
   TF_REDUCE_TRIREME_LOSS1, /* Reduces chance of Trireme being lost at sea */
   TF_REDUCE_TRIREME_LOSS2, /* Reduces chance of Trireme being lost at sea */
   TF_BUILD_AIRBORNE, /* Player can build air units */
+  TF_SPACE_PARTS_INC, /* Increases the number of spaceship parts */
   TF_LAST
 };
 
@@ -152,4 +153,8 @@
   }                                                                         \
 }
 
+/* Does the player know this tech?  */
+#define player_knows_tech(plr, tech)                                        \
+  (get_invention((plr), (tech)) == TECH_KNOWN)
+
 #endif  /* FC__TECH_H */
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.216
diff -u -r1.216 unit.c
--- common/unit.c       31 Aug 2004 04:40:50 -0000      1.216
+++ common/unit.c       1 Sep 2004 01:53:08 -0000
@@ -28,6 +28,7 @@
 #include "support.h"
 #include "tech.h"
 
+#include "city.h"
 #include "unit.h"
 
 /***************************************************************
@@ -53,15 +54,8 @@
   case SEA_MOVING:
     move_rate = (base_move_rate * punit->hp) / unit_type(punit)->hp;
 
-    if (player_owns_active_wonder(unit_owner(punit), B_LIGHTHOUSE)) {
-      move_rate += SINGLE_MOVE;
-    }
- 
-    if (player_owns_active_wonder(unit_owner(punit), B_MAGELLAN)) {
-      move_rate += (improvement_variant(B_MAGELLAN) == 1) 
-                     ? SINGLE_MOVE : 2 * SINGLE_MOVE;
-    }
- 
+    move_rate += get_player_bonus(unit_owner(punit), EFT_SEA_MOVE) * 
SINGLE_MOVE;
+
     if (player_knows_techs_with_flag(unit_owner(punit), TF_BOAT_FAST)) {
       move_rate += SINGLE_MOVE;
     }
@@ -497,14 +491,8 @@
     return AB_TOO_BIG;
   if (pcity->owner != punit->owner)
     return AB_NOT_OWNER;
-  if (improvement_exists(B_AQUEDUCT)
-      && !city_got_building(pcity, B_AQUEDUCT)
-      && new_pop > game.aqueduct_size)
-    return AB_NO_AQUEDUCT;
-  if (improvement_exists(B_SEWER)
-      && !city_got_building(pcity, B_SEWER)
-      && new_pop > game.sewer_size)
-    return AB_NO_SEWER;
+  if (!city_can_grow_to(pcity, new_pop))
+    return AB_NO_SPACE;
   return AB_ADD_OK;
 }
 
@@ -1643,7 +1631,7 @@
 **************************************************************************/
 int base_trireme_loss_pct(struct player *pplayer, struct unit *punit)
 {
-  if (player_owns_active_wonder(pplayer, B_LIGHTHOUSE)) {
+  if (get_player_bonus(pplayer, EFT_NO_SINK_DEEP)) {
     return 0;
   } else if (player_knows_techs_with_flag(pplayer, TF_REDUCE_TRIREME_LOSS2)) {
     return game.trireme_loss_chance[punit->veteran] / 4;
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.122
diff -u -r1.122 unit.h
--- common/unit.h       26 Aug 2004 18:37:52 -0000      1.122
+++ common/unit.h       1 Sep 2004 01:53:08 -0000
@@ -97,11 +97,7 @@
   AB_NOT_OWNER,                        /* Owner of unit is not owner of
                                   city */
   AB_TOO_BIG,                  /* City is too big to be added to */
-  AB_NO_AQUEDUCT,              /* Adding takes city past limit for
-                                  aquaduct but city has no
-                                  aquaduct */
-  AB_NO_SEWER                  /* Adding takes city past limit for
-                                  sewer but city has no sewer */
+  AB_NO_SPACE                  /* Adding takes city past limit */
 };
 
 enum unit_upgrade_result {
Index: common/unittype.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unittype.c,v
retrieving revision 1.39
diff -u -r1.39 unittype.c
--- common/unittype.c   26 Aug 2004 06:26:09 -0000      1.39
+++ common/unittype.c   1 Sep 2004 01:53:08 -0000
@@ -476,7 +476,8 @@
 
   if (!unit_type_exists(id))
     return FALSE;
-  if (unit_type_flag(id, F_NUCLEAR) && game.global_wonders[B_MANHATTEN] == 0)
+  if (unit_type_flag(id, F_NUCLEAR)
+      && !get_player_bonus(p, EFT_ENABLE_NUKE))
     return FALSE;
   if (unit_type_flag(id, F_NOBUILD)) {
     return FALSE;
Index: data/default/buildings.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/buildings.ruleset,v
retrieving revision 1.50
diff -u -r1.50 buildings.ruleset
--- data/default/buildings.ruleset      27 Aug 2004 17:14:42 -0000      1.50
+++ data/default/buildings.ruleset      1 Sep 2004 01:53:08 -0000
@@ -58,19 +58,92 @@
 ; build_cost   = production shields required to build
 ; upkeep       = monetary upkeep value
 ; sabotage     = percent chance of diplomat sabotage being successful
-; effect {     = list of named effects (and parameters thereto):
+; effect {     = list of effects; parameters are:
 ;
 ;   ( See doc/README.effects for information and a listing of effects. )
 ;
-; }              (All effects in list(s) are cumulative.)
-; sound                = optional sound effect associated
-; sound_alt    = optional alternative sound effect if above not
-;                supported in client
-; helptext     = optional help text string; should escape all raw
-;                newlines so that xgettext parsing works
+;   eff                = effect name; e.g. "Tax_Bonus"
+;   range      = effect range; one of:
+;                "Local", "City", "Continent", "Player", "World".
+;                by ommission the range is "City".
+;   value       = modifier value of effect; by ommission +1.
+;   type        = requirement type; one of:
+;                "None", "Tech", "Gov", "Building", "Special", "Terrain".
+;                by ommission the type is "None".
+;   req                = requirement data; varies with requirement type.
+;
+; }              the effects in the list are cumulative.
 ;
 ; */ <-- avoid gettext warnings
 
+;
+; Effect groups are a convenience mechanism to handle
+; equivalent effects which may be done by one of several buildings.
+; The first building in the 'buildings' list of the group which
+; exists wins.
+;
+
+[group_cathedrals]
+name           = "Cathedrals"
+elements       =
+    { "building", "range"
+      "Michelangelo's Chapel", "Player"
+      "Cathedral", "City"
+    }
+
+[group_labs]
+name           = "Labs"
+elements       =
+    { "building", "range"
+      "SETI Program", "Player"
+      "Research Lab", "City"
+    }
+
+[group_generators]
+name           = "Generators"
+elements       =
+    { "building", "range"
+      "Hoover Dam", "Player"
+      "Nuclear Plant", "City"
+      "Hydro Plant", "City"
+      "Power Plant", "City"
+    }
+
+[group_janitors]
+name            = "Janitors"
+elements       =
+    { "building", "range"
+      "Recycling Center", "City"
+      "Hoover Dam", "Player"
+      "Nuclear Plant", "City"
+      "Hydro Plant", "City"
+    }
+
+[group_defenders]
+name           = "Defenders"
+elements       =
+    { "building", "range"
+      "Great Wall", "Player"
+      "City Walls", "City"
+    }
+
+[group_peacekeepers]
+name           = "Peacekeepers"
+elements       =
+    { "building", "range"
+      "Women's Suffrage", "Player"
+      "Police Station", "City"
+    }
+
+[group_purifiers]
+name           = "Purifiers"
+elements       =
+    { "building", "range"
+      "Palace", "City"
+      "Courthouse", "City"
+    }
+
+
 [building_airport]
 name           = _("Airport")
 tech_req       = "Radio"
@@ -88,10 +161,10 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "aff_unit"
-       "Unit_Veteran", "City", "Air"
-       "Unit_Repair", "City", "Air"
-       "Airlift", "City"
+    { "eff"
+      "Air_Veteran"
+      "Air_Regen"
+      "Airlift"
     }
 sound          = "b_airport"
 sound_alt      = "b_generic"
@@ -122,9 +195,9 @@
 build_cost     = 60
 upkeep         = 2
 sabotage       = 100
-effect         =
-    { "type", "range", "amount"
-       "Size_Unlimit", "City", 8
+effect          =
+    { "eff", "value"
+      "Size_Adj", 4
     }
 sound          = "b_aqueduct"
 sound_alt      = "b_generic"
@@ -150,9 +223,9 @@
 upkeep         = 2
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Tax_Bonus", "City", 50, "Marketplace"
-       "Luxury_Bonus", "City", 50, "Marketplace"
+    { "eff", "value", "req_type", "req"
+      "Tax_Bonus", 50, "Building", "Marketplace"
+      "Luxury_Bonus", 50, "Building", "Marketplace"
     }
 sound          = "b_bank"
 sound_alt      = "b_generic"
@@ -174,14 +247,15 @@
 ;equiv_dupl    = 
 equiv_repl     = "Sun Tzu's War Academy","Barracks II", "Barracks III"
 obsolete_by    = "Gunpowder"
+replaced_by    = "Barracks II"
 is_wonder      = 0
 build_cost     = 30
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "aff_unit"
-       "Unit_Veteran", "City", "Land"
-       "Unit_Repair", "City", "Land"
+    { "eff"
+      "Land_Veteran"
+      "Land_Regen"
     }
 sound          = "b_barracks_i"
 sound_alt      = "b_generic"
@@ -205,14 +279,15 @@
 ;equiv_dupl    =
 equiv_repl     = "Sun Tzu's War Academy", "Barracks III"
 obsolete_by    = "Mobile Warfare"
+replaced_by    = "Barracks III"
 is_wonder      = 0
 build_cost     = 30
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "aff_unit"
-       "Unit_Veteran", "City", "Land"
-       "Unit_Repair", "City", "Land"
+    { "eff"
+      "Land_Veteran"
+      "Land_Regen"
     }
 sound          = "b_barracks_ii"
 sound_alt      = "b_generic"
@@ -241,9 +316,9 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "aff_unit"
-       "Unit_Veteran", "City", "Land"
-       "Unit_Repair", "City", "Land"
+    { "eff"
+      "Land_Veteran"
+      "Land_Regen"
     }
 sound          = "b_barracks_iii"
 sound_alt      = "b_generic"
@@ -272,10 +347,10 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_adv"
-       "Make_Content", "City", 3
-       "Make_Content", "City", 1, "Theology"
-       "Make_Content", "City", -1, "Communism"
+    { "eff", "value", "equiv", "req_type", "req"
+      "Make_Content", 3, "Cathedrals"
+      "Make_Content", 1, "Cathedrals", "Tech", "Theology"
+      "Make_Content", -1, "Cathedrals", "Tech", "Communism"
     }
 sound          = "b_cathedral"
 sound_alt      = "b_generic"
@@ -305,11 +380,9 @@
 upkeep         = 0
 sabotage       = 50
 effect         =
-    { "type", "range", "amount", "cond_bldg", "aff_unit"
-       "Unit_Defend", "City", 300, "", "Land"
-       "Unit_No_Lose_Pop", "City", 0, "", "Land"
-       "Spy_Resistant", "Local", 50
-       "Spy_Resistant", "Local", -50, "Palace"
+    { "eff", "value", "equiv"
+      "Land_Defend", 3, "Defenders"
+      "Unit_No_Lose_Pop"
     }
 sound          = "b_city_walls"
 sound_alt      = "b_generic"
@@ -338,8 +411,8 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Defend", "City", 200, "Sea"
+    { "eff", "value"
+      "Sea_Defend", 2
     }
 sound          = "b_coastal_defense"
 sound_alt      = "b_generic"
@@ -365,9 +438,9 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_adv"
-       "Make_Content", "City", 3
-       "Make_Content", "City", 1, "Electricity"
+    { "eff", "value", "req_type", "req"
+      "Make_Content", 3
+      "Make_Content", 1, "Tech", "Electricity"
     }
 sound          = "b_colosseum"
 sound_alt      = "b_generic"
@@ -395,10 +468,11 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_gov"
-       "Corrupt_Pct", "City", 50
-       "Make_Content", "City", 1, "Democracy"
-       "Revolt_Dist_Pct", "City", 50
+    { "eff", "value", "equiv", "req_type", "req"
+      "Corrupt_Pct", 50, "Purifiers"
+      "Waste_Pct", 50, "Purifiers"
+      "Make_Content", 1, "", "Gov", "Democracy"
+      "Incite_Dist_Pct", 75
     }
 sound          = "b_courthouse"
 sound_alt      = "b_generic"
@@ -426,8 +500,8 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Prod_Bonus", "City", 50
+    { "eff", "value"
+      "Prod_Bonus", 50
     }
 sound          = "b_factory"
 sound_alt      = "b_generic"
@@ -453,8 +527,8 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Growth_Food", "City", 50
+    { "eff"
+      "Growth_Food"
     }
 sound          = "b_granary"
 sound_alt      = "b_generic"
@@ -484,8 +558,8 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_terr", "aff_spec"
-       "Food_Add_Tile", "City", 1, "Ocean", "None"
+    { "eff", "value", "req_type", "req"
+       "Food_Add_Tile", 1, "Terrain", "Ocean"
     }
 sound          = "b_harbour"
 sound_alt      = "b_generic"
@@ -511,11 +585,10 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "City", 25, "Factory"
-       "Prod_Bonus", "City", 25, "Mfg. Plant"
-       "Pollu_Prod_Pct", "City", 50
-       "Pollu_Prod_Pct", "City", -50, "Recycling Center"
+    { "eff", "value", "equiv", "req_type", "req"
+      "Prod_Bonus", 25, "Generators", "Building", "Factory"
+      "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant"
+      "Pollu_Prod_Pct", 2, "Janitors"
     }
 sound          = "b_hydro_plant"
 sound_alt      = "b_generic"
@@ -554,8 +627,8 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Science_Bonus", "City", 50
+    { "eff", "value"
+      "Science_Bonus", 50
     }
 sound          = "b_library"
 sound_alt      = "b_generic"
@@ -581,9 +654,9 @@
 upkeep         = 0
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Tax_Bonus", "City", 50
-       "Luxury_Bonus", "City", 50
+    { "eff", "value"
+      "Tax_Bonus", 50
+      "Luxury_Bonus", 50
     }
 sound          = "b_marketplace"
 sound_alt      = "b_generic"
@@ -609,8 +682,8 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Pollu_Pop_Pct", "City", 0
+    { "eff", "value"
+      "Pollu_Pop_Pct", 100
     }
 sound          = "b_mass_transit"
 sound_alt      = "b_generic"
@@ -637,8 +710,8 @@
 upkeep         = 6
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "City", 50, "Factory"
+    { "eff", "value", "req_type", "req"
+      "Prod_Bonus", 50, "Building", "Factory"
     }
 sound          = "b_mfg_plant"
 sound_alt      = "b_generic"
@@ -665,11 +738,10 @@
 upkeep         = 2
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "City", 25, "Factory"
-       "Prod_Bonus", "City", 25, "Mfg. Plant"
-       "Pollu_Prod_Pct", "City", 50
-       "Pollu_Prod_Pct", "City", -50, "Recycling Center"
+    { "eff", "value", "equiv", "req_type", "req"
+      "Prod_Bonus", 25, "Generators", "Building", "Factory"
+      "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant"
+      "Pollu_Prod_Pct", 2, "Janitors"
     }
 sound          = "b_nuclear_plant"
 sound_alt      = "b_generic"
@@ -709,8 +781,8 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_terr", "aff_spec"
-       "Prod_Add_Tile", "City", 1, "Ocean", "None"
+    { "eff", "value", "req_type", "req"
+       "Prod_Add_Tile", 1, "Terrain", "Ocean"
     }
 sound          = "b_offshore_platform"
 sound_alt      = "b_generic"
@@ -736,10 +808,12 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Capital_City", "City"
-       "Capital_Exists", "Player"
-       "Spy_Resistant", "City", 50
+    { "eff", "value", "equiv"
+      "Corrupt_Pct", 50, "Purifiers"
+      "Waste_Pct", 50, "Purifiers"
+      "Spy_Resistant"
+      "No_Incite"
+      "Capital_City"
     }
 sound          = "b_palace"
 sound_alt      = "b_generic"
@@ -773,9 +847,9 @@
 upkeep         = 2
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_gov"
-       "Make_Content_Mil", "City", 1, "Republic"
-       "Make_Content_Mil", "City", 2, "Democracy"
+    { "eff", "value", "equiv", "req_type", "req"
+      "Make_Content_Mil", 1, "Peacekeepers", "Gov", "Republic"
+      "Make_Content_Mil", 2, "Peacekeepers", "Gov", "Democracy"
     }
 sound          = "b_police_station"
 sound_alt      = "b_generic"
@@ -805,9 +879,9 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "aff_unit"
-       "Unit_Veteran", "City", "Sea"
-       "Unit_Repair", "City", "Sea"
+    { "eff"
+      "Sea_Veteran"
+      "Sea_Regen"
     }
 sound          = "b_port_facility"
 sound_alt      = "b_generic"
@@ -834,9 +908,9 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "City", 25, "Factory"
-       "Prod_Bonus", "City", 25, "Mfg. Plant"
+    { "eff", "value", "equiv", "req_type", "req"
+      "Prod_Bonus", 25, "Generators", "Building", "Factory"
+      "Prod_Bonus", 25, "Generators", "Building", "Mfg. Plant"
     }
 sound          = "b_power_plant"
 sound_alt      = "b_generic"
@@ -872,8 +946,8 @@
 upkeep         = 2
 sabotage       = 100
 effect         =
-    { "type", "range", "amount"
-       "Pollu_Prod_Pct", "City", 34
+    { "eff", "value", "equiv"
+      "Pollu_Prod_Pct", 3, "Janitors"
     }
 sound          = "b_recycling_center"
 sound_alt      = "b_generic"
@@ -900,8 +974,8 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Science_Bonus", "City", 50, "Library"
+    { "eff", "value", "equiv", "req_type", "req"
+       "Science_Bonus", 50, "Labs", "Building", "Library"
     }
 sound          = "b_research_lab"
 sound_alt      = "b_generic"
@@ -929,9 +1003,8 @@
 upkeep         = 2
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Defend", "City", 200, "Air"
-       "Unit_Defend", "City", 200, "Missile"
+    { "eff", "value"
+      "Air_Defend", 2
     }
 sound          = "b_sam_battery"
 sound_alt      = "b_generic"
@@ -957,9 +1030,9 @@
 upkeep         = 4
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Nuke_Proof", "City", 3
-       "Unit_Defend", "City", 200, "Missile"
+    { "eff", "value"
+      "Nuke_Proof"
+      "Missile_Defend", 2
     }
 sound          = "b_sdi_defense"
 sound_alt      = "b_generic"
@@ -987,9 +1060,9 @@
 build_cost     = 80
 upkeep         = 2
 sabotage       = 100
-effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Size_Unlimit", "City", 12, "Aqueduct"
+effect          =
+    { "eff", "req_type", "req"
+      "Size_Unlimit", "Building", "Aqueduct"
     }
 sound          = "b_sewer_system"
 sound_alt      = "b_generic"
@@ -1014,13 +1087,6 @@
 build_cost     = 220
 upkeep         = 4
 sabotage       = 100
-effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "City", 25, "Factory"
-       "Prod_Bonus", "City", 25, "Mfg. Plant"
-       "Pollu_Prod_Pct", "City", 0
-       "Slow_Global_Warm", "World", 10
-    }
 sound          = "b_solar_plant"
 sound_alt      = "b_generic"
 ; /* xgettext:no-c-format */
@@ -1057,9 +1123,10 @@
 build_cost     = 160
 upkeep         = 0
 sabotage       = 100
-effect         =
-    { "type", "range", "amount"
-       "Space_Part", "Local", 2
+effect          =
+    { "eff"
+      "Space_Part"
+      "SS_Component"
     }
 sound          = "b_space_component"
 sound_alt      = "b_generic"
@@ -1088,9 +1155,10 @@
 build_cost     = 320
 upkeep         = 0
 sabotage       = 100
-effect         =
-    { "type", "range", "amount"
-       "Space_Part", "Local", 3
+effect          =
+    { "eff"
+      "Space_Part"
+      "SS_Module"
     }
 sound          = "b_space_module"
 sound_alt      = "b_generic"
@@ -1128,9 +1196,10 @@
 build_cost     = 80
 upkeep         = 0
 sabotage       = 100
-effect         =
-    { "type", "range", "amount"
-       "Space_Part", "Local", 1
+effect          =
+    { "eff"
+      "Space_Part"
+      "SS_Structural"
     }
 sound          = "b_space_structural"
 sound_alt      = "b_generic"
@@ -1160,9 +1229,9 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Tax_Bonus", "City", 50, "Bank"
-       "Luxury_Bonus", "City", 50, "Bank"
+    { "eff", "value", "req_type", "req"
+      "Tax_Bonus", 50, "Building", "Bank"
+      "Luxury_Bonus", 50, "Building", "Bank"
     }
 sound          = "b_stock_exchange"
 sound_alt      = "b_generic"
@@ -1189,8 +1258,8 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_terr", "aff_spec"
-       "Trade_Per_Tile", "City", 50, "None", "Road"
+    { "eff", "value", "req_type", "req"
+       "Trade_Per_Tile", 50, "Special", "Road"
     }
 sound          = "b_super_highways"
 sound_alt      = "b_generic"
@@ -1219,8 +1288,8 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "aff_terr", "aff_spec"
-       "Food_Per_Tile", "City", 50, "None", "Farmland"
+    { "eff", "value", "req_type", "req"
+       "Food_Per_Tile", 50, "Special", "Farmland"
     }
 sound          = "b_supermarket"
 sound_alt      = "b_generic"
@@ -1248,9 +1317,9 @@
 upkeep         = 1
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_adv"
-       "Make_Content", "City", 1
-       "Make_Content", "City", 1, "Mysticism"
+    { "eff", "value", "req_type", "req"
+      "Make_Content", 1
+      "Make_Content", 1, "Tech", "Mysticism"
     }
 sound          = "b_temple"
 sound_alt      = "b_generic"
@@ -1277,8 +1346,8 @@
 upkeep         = 3
 sabotage       = 100
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Science_Bonus", "City", 50, "Library"
+    { "eff", "value", "req_type", "req"
+      "Science_Bonus", 50, "Building", "Library"
     }
 sound          = "b_university"
 sound_alt      = "b_generic"
@@ -1305,9 +1374,9 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "survives"
-       "Reveal_Map", "Player", 0
-       "Enable_Space", "World", 1
+    { "eff", "range", "survives"
+      "Reveal_Map", "Player", 0
+      "Enable_Space", "World", 1
     }
 sound          = "w_apollo_program"
 sound_alt      = "w_generic"
@@ -1334,8 +1403,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Upkeep_Free", "Player", 1
+    { "eff", "range", "value"
+      "Upkeep_Free", "Player", 1
     }
 sound          = "w_asmiths_trading_co"
 sound_alt      = "w_generic"
@@ -1361,8 +1430,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Trade_Inc_Tile", "City", 1
+    { "eff", "value"
+      "Trade_Inc_Tile", 1
     }
 sound          = "w_colossus"
 sound_alt      = "w_generic"
@@ -1388,8 +1457,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Science_Bonus", "City", 50
+    { "eff", "value"
+      "Science_Bonus", 50
     }
 sound          = "w_copernicus_observatory"
 sound_alt      = "w_generic"
@@ -1415,8 +1484,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Make_Content", "Player", 1
+    { "eff", "range", "value"
+      "Force_Content", "Player", 1
     }
 sound          = "w_cure_for_cancer"
 sound_alt      = "w_generic"
@@ -1444,8 +1513,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Give_Imm_Adv", "Player", 2
+    { "eff", "range", "value"
+      "Give_Imm_Tech", "Player", 2
     }
 sound          = "w_darwins_voyage"
 sound_alt      = "w_generic"
@@ -1471,10 +1540,6 @@
 build_cost     = 300
 upkeep         = 0
 sabotage       = 0
-effect         =
-    { "type", "range", "amount"
-       "Improve_Rep", "Player", 25
-    }
 sound          = "w_eiffel_tower"
 sound_alt      = "w_generic"
 ; /* xgettext:no-c-format */
@@ -1502,8 +1567,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Adv_Parasite", "Player", 2
+    { "eff", "range", "value"
+      "Tech_Parasite", "Player", 2
     }
 sound          = "w_great_library"
 sound_alt      = "w_generic"
@@ -1529,9 +1594,9 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Defend", "Player", 300, "Land"
-       "Unit_No_Lose_Pop", "Player", 0, "Land"
+    { "eff", "range", "value", "equiv"
+      "Land_Defend", "Player", 3, "Defenders"
+      "Unit_No_Lose_Pop", "Player"
     }
 sound          = "w_great_wall"
 sound_alt      = "w_generic"
@@ -1559,9 +1624,9 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Make_Happy", "Player", 1
-       "Make_Happy", "City", 2
+    { "eff", "range", "value"
+      "Make_Happy", "Player", 1
+      "Make_Happy", "City", 2
     }
 sound          = "w_hanging_gardens"
 sound_alt      = "w_generic"
@@ -1590,11 +1655,10 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Prod_Bonus", "Player", 25, "Factory"
-       "Prod_Bonus", "Player", 25, "Mfg. Plant"
-       "Pollu_Prod_Pct", "Player", 50
-       "Pollu_Prod_Pct", "Player", -50, "Recycling Center"
+    { "eff", "range", "value", "equiv", "req_type", "req"
+      "Prod_Bonus", "Player", 25, "Generators", "Building", "Factory"
+      "Prod_Bonus", "Player", 25, "Generators", "Building", "Mfg. Plant"
+      "Pollu_Prod_Pct", "Player", 2, "Janitors"
     }
 sound          = "w_hoover_dam"
 sound_alt      = "w_generic"
@@ -1620,8 +1684,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Science_Bonus", "City", 100
+    { "eff", "value"
+      "Science_Bonus", 100
     }
 sound          = "w_isaac_newtons_college"
 sound_alt      = "w_generic"
@@ -1647,8 +1711,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Make_Content", "Player", 2
+    { "eff", "range", "value"
+      "Force_Content", "Player", 2
     }
 sound          = "w_js_bachs_cathedral"
 sound_alt      = "w_generic"
@@ -1673,8 +1737,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Prod_Add_Tile", "City", 1
+    { "eff", "value"
+      "Prod_Add_Tile", 1
     }
 sound          = "w_king_richards_crusade"
 sound_alt      = "w_generic"
@@ -1691,7 +1755,7 @@
 graphic_alt    = "-"
 ;terr_gate     =
 ;spec_gate     =
-equiv_range    = "Player"
+equiv_range    = "None"
 ;equiv_dupl    =
 ;equiv_repl    =
 obsolete_by    = "Automobile"
@@ -1700,8 +1764,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Upgrade_One_Leap", "Player", 100
+    { "eff", "range"
+      "Upgrade_One_Leap", "Player"
     }
 sound          = "w_leonardos_workshop"
 sound_alt      = "w_generic"
@@ -1726,10 +1790,10 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Move", "Player", 1, "Sea"
-       "No_Sink_Deep", "Player"
-       "Unit_Veteran", "Player", 0, "Sea"
+    { "eff", "range", "value"
+      "Sea_Move", "Player", 1
+      "No_Sink_Deep", "Player"
+      "Sea_Veteran", "Player"
     }
 sound          = "w_lighthouse"
 sound_alt      = "w_generic"
@@ -1747,7 +1811,7 @@
 graphic_alt    = "-"
 ;terr_gate     =
 ;spec_gate     =
-equiv_range    = "Player"
+equiv_range    = "None"
 ;equiv_dupl    =
 ;equiv_repl    =
 obsolete_by    = "None"
@@ -1756,8 +1820,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Move", "Player", 2, "Sea"
+    { "eff", "range", "value"
+      "Sea_Move", "Player", 2
     }
 sound          = "w_magellans_expedition"
 sound_alt      = "w_generic"
@@ -1782,8 +1846,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "survives"
-       "Enable_Nuke", "World", 1
+    { "eff", "range", "survives"
+      "Enable_Nuke", "World", 1
     }
 sound          = "w_manhattan_project"
 sound_alt      = "w_generic"
@@ -1807,8 +1871,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range"
-       "Have_Embassies", "Player"
+    { "eff", "range"
+      "Have_Embassies", "Player"
     }
 sound          = "w_marco_polos_embassy"
 sound_alt      = "w_generic"
@@ -1833,10 +1897,10 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "cond_adv"
-       "Make_Content", "Player", 3
-       "Make_Content", "Player", 1, "Theology"
-       "Make_Content", "Player", -1, "Communism"
+    { "eff", "range", "value", "equiv", "req_type", "req"
+      "Make_Content", "Player", 3, "Cathedrals"
+      "Make_Content", "Player", 1, "Cathedrals", "Tech", "Theology"
+      "Make_Content", "Player", -1, "Cathedrals", "Tech", "Communism"
     }
 sound          = "w_michelangelos_chapel"
 sound_alt      = "w_generic"
@@ -1866,9 +1930,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "cond_bldg", "cond_adv"
-       "Make_Content", "Player", 1, "Temple"
-       "Make_Content", "Player", 1, "Temple", "Mysticism"
+    { "eff", "value", "req_type", "req"
+      "Make_Content", 2, "Building", "Temple"
     }
 sound          = "w_oracle"
 sound_alt      = "w_generic"
@@ -1893,8 +1956,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Growth_Food", "Player", 50
+    { "eff", "range"
+      "Growth_Food", "Player"
     }
 sound          = "w_pyramids"
 sound_alt      = "w_generic"
@@ -1919,8 +1982,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "cond_bldg"
-       "Science_Bonus", "Player", 50, "Library"
+    { "eff", "range", "value", "equiv", "req_type", "req"
+      "Science_Bonus", "Player", 50, "Labs", "Building", "Library"
     }
 sound          = "w_seti_program"
 sound_alt      = "w_generic"
@@ -1946,8 +2009,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Make_Content", "City", 99
+    { "eff"
+      "No_Unhappy"
     }
 sound          = "w_shakespeares_theatre"
 sound_alt      = "w_generic"
@@ -1972,9 +2035,9 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range"
-       "Any_Government", "Player"
-       "No_Anarchy", "Player"
+    { "eff", "range"
+      "Any_Government", "Player"
+      "No_Anarchy", "Player"
     }
 sound          = "w_statue_of_liberty"
 sound_alt      = "w_generic"
@@ -2001,9 +2064,10 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Veteran", "Player", 0, "Land"
-       "Unit_Vet_Combat", "Player", 100, "Land"
+    { "eff", "range", "value"
+      "Land_Veteran", "Player"
+      "Land_Regen", "Player"
+      "Land_Vet_Combat", "Player", 50
     }
 sound          = "w_sun_tzus_war_academy"
 sound_alt      = "w_generic"
@@ -2030,12 +2094,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "aff_unit"
-       "Unit_Recover", "Player", 2, "Air"
-       "Unit_Recover", "Player", 2, "Helicopter"
-       "Unit_Recover", "Player", 2, "Land"
-       "Unit_Recover", "Player", 2, "Missile"
-       "Unit_Recover", "Player", 2, "Sea"
+    { "eff", "range", "value"
+      "Unit_Recover", "Player", 2
     }
 sound          = "w_united_nations"
 sound_alt      = "w_generic"
@@ -2068,9 +2128,9 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount", "cond_gov"
-       "Make_Content_Mil", "Player", 1, "Republic"
-       "Make_Content_Mil", "Player", 2, "Democracy"
+    { "eff", "range", "value", "equiv", "req_type", "req"
+      "Make_Content_Mil", "Player", 1, "Peacekeepers", "Gov", "Republic"
+      "Make_Content_Mil", "Player", 2, "Peacekeepers", "Gov", "Democracy"
     }
 sound          = "w_womens_suffrage"
 sound_alt      = "w_generic"
@@ -2106,8 +2166,8 @@
 upkeep         = 0
 sabotage       = 0
 effect         =
-    { "type", "range", "amount"
-       "Prod_To_Gold", "City", 100
+    { "eff"
+      "Prod_To_Gold"
     }
 ; FIXME: this is the real helptext; restore when have a subordnate analogue
 ; /* (ignore for gettext until fixed)
@@ -2124,14 +2184,16 @@
 ")
 
 
-; FIXME: remove all of the following when gen-impr implemented...
-
 [b_special]
 
 ; Special values:
 
-aqueduct_size=8;
-sewer_size=12;
+aqueduct_size=8
+default="Coinage"
+
+; FIXME: remove all of the following when gen-impr implemented...
+
+sewer_size=12
 
 ; Techs which modify building effects:
 
@@ -2139,3 +2201,4 @@
 cathedral_minus="Communism"
 colosseum_plus="Electricity"
 temple_plus="Mysticism"
+
Index: data/default/techs.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/techs.ruleset,v
retrieving revision 1.23
diff -u -r1.23 techs.ruleset
--- data/default/techs.ruleset  12 Aug 2004 20:59:00 -0000      1.23
+++ data/default/techs.ruleset  1 Sep 2004 01:53:08 -0000
@@ -552,7 +552,7 @@
 name     = _("Plastics")
 req1     = "Refining"
 req2     = "Space Flight"
-flags    = "Population_Pollution_Inc"
+flags    = "Population_Pollution_Inc","Space_Parts_Inc"
 graphic     = "a.plastics"
 graphic_alt = "-"
 
@@ -648,7 +648,7 @@
 name     = _("Space Flight")
 req1     = "Computers"
 req2     = "Rocketry"
-flags    = ""
+flags    = "Space_Parts_Inc"
 graphic     = "a.space_flight"
 graphic_alt = "-"
 
@@ -680,7 +680,7 @@
 name     = _("Superconductors")
 req1     = "Nuclear Power"
 req2     = "Laser"
-flags    = ""
+flags    = "Space_Parts_Inc"
 graphic     = "a.superconductors"
 graphic_alt = "-"
 
Index: server/citytools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/citytools.c,v
retrieving revision 1.271
diff -u -r1.271 citytools.c
--- server/citytools.c  31 Aug 2004 04:40:50 -0000      1.271
+++ server/citytools.c  1 Sep 2004 01:53:09 -0000
@@ -384,17 +384,6 @@
   return tempname;
 }
 
-/****************************************************************
-...
-*****************************************************************/
-bool city_got_barracks(struct city *pcity)
-{
-  return (city_affected_by_wonder(pcity, B_SUNTZU) ||
-         city_got_building(pcity, B_BARRACKS) || 
-         city_got_building(pcity, B_BARRACKS2) ||
-         city_got_building(pcity, B_BARRACKS3));
-}
-
 /****************************************************************************
   Return TRUE iff the city can sell the given improvement.
 ****************************************************************************/
@@ -437,14 +426,13 @@
                                 G_BUILD_VETERAN_DIPLOMAT) ? 1 : 0);
   }
     
-  if (is_ground_unittype(id) || improvement_variant(B_BARRACKS) == 1) {
-    return (city_got_barracks(pcity) ? 1 : 0);
+  if (is_ground_unittype(id)) {
+    return (get_city_bonus(pcity, EFT_LAND_VETERAN) ? 1 : 0);
   } else {
     if (is_water_unit(id)) {
-      return ((city_affected_by_wonder(pcity, B_LIGHTHOUSE)
-               || city_got_building(pcity, B_PORT)) ? 1 : 0);
+      return (get_city_bonus(pcity, EFT_SEA_VETERAN) ? 1 : 0);
     } else {
-      return (city_got_building(pcity, B_AIRPORT) ? 1 : 0);
+      return (get_city_bonus(pcity, EFT_AIR_VETERAN) ? 1 : 0);
     }
   }
   
@@ -651,7 +639,7 @@
 
   /* We don't use city_remove_improvement here as the global effects
      stuff has already been handled by transfer_city */
-  pcity->improvements[B_PALACE]=I_NONE;
+  pcity->improvements[game.palace_building]=I_NONE;
 
   /* land barbarians are more likely to destroy city improvements */
   if (is_land_barbarian(city_owner(pcity)))
@@ -710,7 +698,7 @@
 
   pnew_capital = city_list_get(&pplayer->cities, myrand(size));
 
-  city_add_improvement(pnew_capital, B_PALACE);
+  city_add_improvement(pnew_capital, game.palace_building);
 
   /*
    * send_player_cities will recalculate all cities and send them to
@@ -743,7 +731,7 @@
   struct unit_list old_city_units;
   struct player *pgiver = city_owner(pcity);
   int old_trade_routes[NUM_TRADEROUTES];
-  bool had_palace = pcity->improvements[B_PALACE] != I_NONE;
+  bool had_palace = pcity->improvements[game.palace_building] != I_NONE;
   char old_city_name[MAX_LEN_NAME];
 
   assert(pgiver != ptaker);
@@ -1014,7 +1002,8 @@
   int o, x, y;
   struct player *pplayer = city_owner(pcity);
   struct tile *ptile = map_get_tile(pcity->x, pcity->y);
-  bool effect_update, had_palace = pcity->improvements[B_PALACE] != I_NONE;
+  bool effect_update,
+  had_palace = pcity->improvements[game.palace_building] != I_NONE;
   char *city_name = mystrdup(pcity->name);
 
   gamelog(GAMELOG_LOSEC, _("%s lose %s (%i,%i)"),
Index: server/citytools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/citytools.h,v
retrieving revision 1.55
diff -u -r1.55 citytools.h
--- server/citytools.h  6 Aug 2004 16:46:24 -0000       1.55
+++ server/citytools.h  1 Sep 2004 01:53:09 -0000
@@ -30,7 +30,6 @@
 #define POLLUTION_WEIGHTING 14 /* tentative */
 #define WARMING_FACTOR 50
 
-bool city_got_barracks(struct city *pcity);
 bool can_sell_building(struct city *pcity, Impr_Type_id id);
 struct city *find_city_wonder(Impr_Type_id id);
 int build_points_left(struct city *pcity);
@@ -39,6 +38,7 @@
 int city_luxury_bonus(struct city *pcity);
 int city_science_bonus(struct city *pcity);
 int city_tax_bonus(struct city *pcity);
+int city_luxury_bonus(struct city *pcity);
 
 void transfer_city_units(struct player *pplayer, struct player *pvictim, 
                         struct unit_list *units, struct city *pcity,
Index: server/cityturn.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityturn.c,v
retrieving revision 1.258
diff -u -r1.258 cityturn.c
--- server/cityturn.c   28 Aug 2004 19:15:39 -0000      1.258
+++ server/cityturn.c   1 Sep 2004 01:53:09 -0000
@@ -67,11 +67,10 @@
 static bool city_build_building(struct player *pplayer, struct city *pcity);
 static bool city_build_unit(struct player *pplayer, struct city *pcity);
 static bool city_build_stuff(struct player *pplayer, struct city *pcity);
-static int improvement_upgrades_to(struct city *pcity, int imp);
+static Impr_Type_id building_upgrades_to(struct city *pcity, Impr_Type_id id);
 static void upgrade_building_prod(struct city *pcity);
 static Unit_Type_id unit_upgrades_to(struct city *pcity, Unit_Type_id id);
 static void upgrade_unit_prod(struct city *pcity);
-static void obsolete_building_test(struct city *pcity, int b1, int b2);
 static void pay_for_buildings(struct player *pplayer, struct city *pcity);
 
 static bool disband_city(struct city *pcity);
@@ -307,10 +306,10 @@
     turns_growth = (city_granary_size(pcity->size) - pcity->food_stock - 1)
                   / pcity->food_surplus;
 
-    if (!city_got_effect(pcity,B_GRANARY) && !pcity->is_building_unit
-       && pcity->currently_building == B_GRANARY
+    if (!get_city_bonus(pcity, EFT_GROWTH_FOOD)
+       && get_current_construction_bonus(pcity, EFT_GROWTH_FOOD)
        && pcity->shield_surplus > 0) {
-      turns_granary = (impr_build_shield_cost(B_GRANARY)
+      turns_granary = (impr_build_shield_cost(pcity->currently_building)
                       - pcity->shield_stock) / pcity->shield_surplus;
       /* if growth and granary completion occur simultaneously, granary
         preserves food.  -AJS */
@@ -320,7 +319,7 @@
                         E_CITY_GRAN_THROTTLE,
                         _("Game: Suggest throttling growth in %s to use %s "
                           "(being built) more effectively."), pcity->name,
-                        improvement_types[B_GRANARY].name);
+                        improvement_types[pcity->currently_building].name);
       }
     }
 
@@ -431,40 +430,20 @@
 {
   struct player *powner = city_owner(pcity);
   bool have_square;
-  bool has_granary = city_got_effect(pcity, B_GRANARY);
+  bool has_granary = get_city_bonus(pcity, EFT_GROWTH_FOOD);
   bool rapture_grow = city_rapture_grow(pcity); /* check before size increase! 
*/
   int new_food;
 
-  if (!city_got_building(pcity, B_AQUEDUCT)
-      && pcity->size>=game.aqueduct_size) {/* need aqueduct */
-    if (!pcity->is_building_unit && pcity->currently_building == B_AQUEDUCT) {
+  if (!city_can_grow_to(pcity, pcity->size + 1)) { /* need improvement */
+    if (get_current_construction_bonus(pcity, EFT_SIZE_ADJ) > 0) {
       notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQ_BUILDING,
                       _("Game: %s needs %s (being built) "
                         "to grow any further."), pcity->name,
-                      improvement_types[B_AQUEDUCT].name);
+                      improvement_types[pcity->currently_building].name);
     } else {
       notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT,
-                      _("Game: %s needs %s to grow any further."),
-                      pcity->name, improvement_types[B_AQUEDUCT].name);
-    }
-    /* Granary can only hold so much */
-    new_food = (city_granary_size(pcity->size) *
-               (100 - game.aqueductloss / (1 + (has_granary ? 1 : 0)))) / 100;
-    pcity->food_stock = MIN(pcity->food_stock, new_food);
-    return;
-  }
-
-  if (!city_got_building(pcity, B_SEWER)
-      && pcity->size>=game.sewer_size) {/* need sewer */
-    if (!pcity->is_building_unit && pcity->currently_building == B_SEWER) {
-      notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQ_BUILDING,
-                      _("Game: %s needs %s (being built) "
-                        "to grow any further."), pcity->name,
-                      improvement_types[B_SEWER].name);
-    } else {
-      notify_player_ex(powner, pcity->x, pcity->y, E_CITY_AQUEDUCT,
-                      _("Game: %s needs %s to grow any further."),
-                      pcity->name, improvement_types[B_SEWER].name);
+                      _("Game: %s needs an improvement to grow any further."),
+                      pcity->name);
     }
     /* Granary can only hold so much */
     new_food = (city_granary_size(pcity->size) *
@@ -547,7 +526,7 @@
                         pcity->name, utname);
        gamelog(GAMELOG_UNITFS, _("%s lose %s (famine)"),
                get_nation_name_plural(city_owner(pcity)->nation), utname);
-       if (city_got_effect(pcity, B_GRANARY))
+       if (get_city_bonus(pcity, EFT_GROWTH_FOOD))
          pcity->food_stock=city_granary_size(pcity->size)/2;
        else
          pcity->food_stock=0;
@@ -557,7 +536,7 @@
     notify_player_ex(city_owner(pcity), pcity->x, pcity->y, E_CITY_FAMINE,
                     _("Game: Famine causes population loss in %s."),
                     pcity->name);
-    if (city_got_effect(pcity, B_GRANARY))
+    if (get_city_bonus(pcity, EFT_GROWTH_FOOD))
       pcity->food_stock = city_granary_size(pcity->size - 1) / 2;
     else
       pcity->food_stock = 0;
@@ -570,31 +549,12 @@
 **************************************************************************/
 void advisor_choose_build(struct player *pplayer, struct city *pcity)
 {
-  struct ai_choice choice;
   Impr_Type_id id = -1;
-  int want=0;
-
-  init_choice(&choice);
-  if (!city_owner(pcity)->ai.control) {
-    /* so that ai_advisor is smart even for humans */
-    ai_eval_buildings(pcity);
-  }
-  ai_advisor_choose_building(pcity, &choice); /* much smarter version -- Syela 
*/
-  freelog(LOG_DEBUG, "Advisor_choose_build got %d/%d"
-         " from ai_advisor_choose_building.",
-         choice.choice, choice.want);
-  id = choice.choice;
-  want = choice.want;
-
-  if (id >= 0 && id < B_LAST && want > 0) {
-    change_build_target(pplayer, pcity, id, FALSE, E_IMP_AUTO);
-    /* making something. */
-    return;
-  }
 
   /* Build something random, undecided. */
   impr_type_iterate(i) {
-    if (can_build_improvement(pcity, i) && i != B_PALACE) {
+    if (can_build_improvement(pcity, i)
+       && !building_has_effect(i, EFT_CAPITAL_CITY)) {
       id = i;
       break;
     }
@@ -675,7 +635,7 @@
        target = new_target;
       }
     } else if (!is_unit && !can_build_improvement(pcity, target)) {
-      Impr_Type_id new_target = improvement_upgrades_to(pcity, target);
+      Impr_Type_id new_target = building_upgrades_to(pcity, target);
 
       /* If the city can never build this improvement, drop it. */
       if (!can_eventually_build_improvement(pcity, new_target)) {
@@ -758,45 +718,47 @@
 }
 
 /**************************************************************************
-...
+  Follow the list of replaced_by buildings until we hit something that
+  we can build.  Return id if we can't upgrade at all.  NB:  returning
+  id doesn't guarantee that pcity really _can_ build id; just that
+  pcity can't build whatever _obsoletes_ id.
 **************************************************************************/
-static void obsolete_building_test(struct city *pcity, int b1, int b2)
+static Impr_Type_id building_upgrades_to(struct city *pcity, Impr_Type_id id)
 {
-  if (pcity->currently_building == b1
-      && !pcity->is_building_unit
-      && can_build_improvement(pcity, b2)) {
-    pcity->currently_building = b2;
+  Impr_Type_id check = id, latest_ok = id;
+
+  if (!can_build_improvement_direct(pcity, check)) {
+    return -1;
+  }
+  while(improvement_exists(check = improvement_types[check].replaced_by)) {
+    if (can_build_improvement_direct(pcity, check)) {
+      latest_ok = check;
+    }
+  }
+  if (latest_ok == id) {
+    return -1; /* Can't upgrade */
   }
-}
 
-/**************************************************************************
-  If imp is obsolete, return the improvement that _can_ be built that
-  lead to imp's obsolesence.
-  !!! Note:  I hear that the building ruleset code is going to be
-  overhauled soon.  If this happens, then this function should be updated
-  to follow the new model.  This function will probably look a lot like
-  unit_upgrades_to().
-**************************************************************************/
-static int improvement_upgrades_to(struct city *pcity, int imp)
-{
-  if (imp == B_BARRACKS && can_build_improvement(pcity, B_BARRACKS3))
-    return B_BARRACKS3;
-  else if (imp == B_BARRACKS && can_build_improvement(pcity, B_BARRACKS2))
-    return B_BARRACKS2;
-  else if (imp == B_BARRACKS2 && can_build_improvement(pcity, B_BARRACKS3))
-    return B_BARRACKS3;
-  else
-    return imp;
+  return latest_ok;
 }
 
 /**************************************************************************
-...
+  Try to upgrade production in pcity.
 **************************************************************************/
 static void upgrade_building_prod(struct city *pcity)
 {
-  obsolete_building_test(pcity, B_BARRACKS,B_BARRACKS3);
-  obsolete_building_test(pcity, B_BARRACKS,B_BARRACKS2);
-  obsolete_building_test(pcity, B_BARRACKS2,B_BARRACKS3);
+  struct player *pplayer = city_owner(pcity);
+  int id = pcity->currently_building;
+  int id2 = building_upgrades_to(pcity, pcity->currently_building);
+
+  if (can_build_improvement(pcity, id2)) {
+    pcity->currently_building = id2;
+    notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_UPGRADED, 
+                 _("Game: Production of %s is upgraded to %s in %s."),
+                 get_improvement_type(id)->name, 
+                 get_improvement_type(id2)->name , 
+                 pcity->name);
+  }
 }
 
 /**************************************************************************
@@ -903,6 +865,7 @@
 static bool city_build_building(struct player *pplayer, struct city *pcity)
 {
   bool space_part;
+  int mod;
 
   if (get_current_construction_bonus(pcity, EFT_PROD_TO_GOLD) > 0) {
     assert(pcity->shield_surplus >= 0);
@@ -924,21 +887,21 @@
   }
   if (pcity->shield_stock
       >= impr_build_shield_cost(pcity->currently_building)) {
-    if (pcity->currently_building == B_PALACE) {
+    if (pcity->currently_building == game.palace_building) {
       city_list_iterate(pplayer->cities, palace) {
-       if (city_got_building(palace, B_PALACE)) {
-         city_remove_improvement(palace, B_PALACE);
+       if (city_got_building(palace, game.palace_building)) {
+         city_remove_improvement(palace, game.palace_building);
          break;
        }
       } city_list_iterate_end;
     }
 
     space_part = TRUE;
-    if (pcity->currently_building == B_SSTRUCTURAL) {
+    if (get_current_construction_bonus(pcity, EFT_SS_STRUCTURAL)) {
       pplayer->spaceship.structurals++;
-    } else if (pcity->currently_building == B_SCOMP) {
+    } else if (get_current_construction_bonus(pcity, EFT_SS_COMPONENT)) {
       pplayer->spaceship.components++;
-    } else if (pcity->currently_building == B_SMODULE) {
+    } else if (get_current_construction_bonus(pcity, EFT_SS_MODULE)) {
       pplayer->spaceship.modules++;
     } else {
       space_part = FALSE;
@@ -971,38 +934,32 @@
                     _("Game: %s has finished building %s."), pcity->name,
                     improvement_types[pcity->currently_building].name);
 
-    if (pcity->currently_building == B_DARWIN) {
-      Tech_Type_id first, second;
-      char buffer[200];
 
-      notify_player(pplayer, _("Game: %s boosts research, "
-                              "you gain 2 immediate advances."),
-                   improvement_types[B_DARWIN].name);
+    if ((mod = get_current_construction_bonus(pcity, EFT_GIVE_IMM_TECH))) {
+      int i;
 
-      if (pplayer->research.researching == A_UNSET) {
-        choose_random_tech(pplayer);
-      }
-      do_free_cost(pplayer);
-      first = pplayer->research.researching;
-      found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, 
-                     A_NONE);
+      notify_player(pplayer, _("Game: %s boosts research, "
+                              "you gain %d immediate advances."),
+                   improvement_types[pcity->currently_building].name,
+                   mod);
+
+      for (i = 0; i < mod; i++) {
+       Tech_Type_id tech = pplayer->research.researching;
+
+       if (tech == A_UNSET) {
+         choose_random_tech(pplayer);
+         tech = pplayer->research.researching;
+       }
+       do_free_cost(pplayer);
+       found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, 
+                      A_NONE);
 
-      if (pplayer->research.researching == A_UNSET) {
-        choose_random_tech(pplayer);
+       notify_embassies(pplayer, NULL,
+           _("Game: The %s have acquired %s from %s."),
+           get_nation_name_plural(pplayer->nation),
+           get_tech_name(pplayer, tech),
+           improvement_types[pcity->currently_building].name);
       }
-      do_free_cost(pplayer);
-      second = pplayer->research.researching;
-      found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
-                     A_NONE);
-
-      (void) mystrlcpy(buffer, get_tech_name(pplayer, first),
-                      sizeof(buffer));
-
-      notify_embassies(pplayer, NULL,
-                      _("Game: The %s have acquired %s and %s from %s."),
-                      get_nation_name_plural(pplayer->nation), buffer,
-                      get_tech_name(pplayer, second),
-                      improvement_types[B_DARWIN].name);
     }
     if (space_part && pplayer->spaceship.state == SSHIP_NONE) {
       notify_player_ex(NULL, pcity->x, pcity->y, E_SPACESHIP,
@@ -1200,7 +1157,10 @@
   struct city *capital;
   int dist, size, cost;
 
-  if (city_got_building(pcity, B_PALACE)) {
+  if (government_has_flag(get_gov_pcity(pcity), G_UNBRIBABLE)) {
+    return INCITE_IMPOSSIBLE_COST;
+  }
+  if (get_city_bonus(pcity, EFT_NO_INCITE)) {
     return INCITE_IMPOSSIBLE_COST;
   }
 
@@ -1250,9 +1210,7 @@
     /* No capital? Take max penalty! */
     dist = 32;
   }
-  if (city_got_building(pcity, B_COURTHOUSE)) {
-    dist /= 4;
-  }
+  dist -= (dist * get_city_bonus(pcity, EFT_INCITE_DIST_PCT)) / 100;
   if (g->fixed_corruption_distance != 0) {
     dist = MIN(g->fixed_corruption_distance, dist);
   }
@@ -1358,7 +1316,7 @@
 
     pcity->did_sell=FALSE;
     pcity->did_buy = FALSE;
-    if (city_got_building(pcity, B_AIRPORT))
+    if (get_city_bonus(pcity, EFT_AIRLIFT))
       pcity->airlift=TRUE;
     else
       pcity->airlift=FALSE;
Index: server/diplomats.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplomats.c,v
retrieving revision 1.58
diff -u -r1.58 diplomats.c
--- server/diplomats.c  26 Jul 2004 19:52:02 -0000      1.58
+++ server/diplomats.c  1 Sep 2004 01:53:10 -0000
@@ -737,7 +737,6 @@
                     struct city *pcity)
 {
   struct player *cplayer;
-  struct city *capital;
   int revolt_cost;
 
   /* Fetch target civilization's player.  Sanity checks. */
@@ -758,11 +757,10 @@
   }
 
   /* Check for city being the capital. */
-  capital = find_palace (city_owner (pcity));
-  if (pcity == capital) {
+  if (get_city_bonus(pcity, EFT_NO_INCITE)) {
     notify_player_ex(pplayer, pcity->x, pcity->y, E_MY_DIPLOMAT_FAILED,
-                    _("Game: You can't subvert the capital of a nation."));
-    freelog (LOG_DEBUG, "incite: city is the capital");
+                    _("Game: You can't subvert this city."));
+    freelog (LOG_DEBUG, "incite: city is protected");
     return;
   }
 
@@ -1031,7 +1029,8 @@
      * City Walls, then there is a 50% chance of getting caught.
      */
     vulnerability = get_improvement_type(improvement)->sabotage;
-    if (city_got_building(pcity, B_CAPITAL)) {
+
+    if (get_city_bonus(pcity, EFT_SPY_RESISTANT)) {
       vulnerability /= 2;
     }
     if (myrand(100) >= vulnerability) {
@@ -1120,7 +1119,7 @@
   def += (def/5.0) * pdefender->veteran;
 
   if (pdefender_tile->city) {
-    if (city_got_building(pdefender_tile->city, B_PALACE)) {
+    if (get_city_bonus(pdefender_tile->city, EFT_SPY_RESISTANT)) {
       def = (def * 3) / 2;/* +50% */
     }
   } else {
Index: server/gotohand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
retrieving revision 1.181
diff -u -r1.181 gotohand.c
--- server/gotohand.c   9 Aug 2004 05:24:35 -0000       1.181
+++ server/gotohand.c   1 Sep 2004 01:53:10 -0000
@@ -923,7 +923,7 @@
   struct unit *passenger;
   struct player *pplayer = unit_owner(punit);
   bool afraid_of_sinking = (unit_flag(punit, F_TRIREME) && 
-                           !player_owns_active_wonder(pplayer, B_LIGHTHOUSE));
+                           !get_player_bonus(pplayer, EFT_NO_SINK_DEEP));
   /* 
    * If the destination is one step away, look around first or just go
    * there?
@@ -1005,17 +1005,20 @@
      */
     defence_multiplier = 2;
     if (pcity) {
-      if (city_got_citywalls(pcity)) {
-       defence_multiplier += 2;
+      int mod;
+
+      if ((mod = get_city_bonus(pcity, EFT_LAND_DEFEND)) > 0) {
+       defence_multiplier += (mod - 1);
       }
-      if (city_got_building(pcity, B_SDI)) {
-       defence_multiplier++;
+
+      if ((mod = get_city_bonus(pcity, EFT_MISSILE_DEFEND)) > 0) {
+       defence_multiplier += (mod - 1);
       }
-      if (city_got_building(pcity, B_SAM)) {
-       defence_multiplier++;
+      if ((mod = get_city_bonus(pcity, EFT_AIR_DEFEND)) > 0) {
+       defence_multiplier += (mod - 1);
       }
-      if (city_got_building(pcity, B_COASTAL)) {
-       defence_multiplier++;
+      if ((mod = get_city_bonus(pcity, EFT_SEA_DEFEND)) > 0) {
+       defence_multiplier += (mod - 1);
       }
     }
 
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.319
diff -u -r1.319 plrhand.c
--- server/plrhand.c    27 Aug 2004 17:36:53 -0000      1.319
+++ server/plrhand.c    1 Sep 2004 01:53:10 -0000
@@ -126,33 +126,31 @@
 /**************************************************************************
 ...
 **************************************************************************/
-void great_library(struct player *pplayer)
+void do_tech_parasite_effect(struct player *pplayer)
 {
-  if (wonder_obsolete(B_GREAT)) 
-    return;
-  if (find_city_wonder(B_GREAT)) {
-    if (pplayer->player_no==find_city_wonder(B_GREAT)->owner) {
-      tech_type_iterate(i) {
-       if (get_invention(pplayer, i) != TECH_KNOWN
-           && tech_is_available(pplayer, i)
-           && game.global_advances[i]>=2) {
-         notify_player_ex(pplayer, -1, -1, E_TECH_GAIN,
-                          _("Game: %s acquired from The Great Library!"),
-                          advances[i].name);
-         gamelog(GAMELOG_TECH, _("%s discover %s (Library)"),
-                 get_nation_name_plural(pplayer->nation), advances[i].name);
-         notify_embassies(pplayer, NULL,
-                          _("Game: The %s have acquired %s"
-                            " from the Great Library."),
-                          get_nation_name_plural(pplayer->nation),
-                          advances[i].name);
-
-         do_free_cost(pplayer);
-         found_new_tech(pplayer, i, FALSE, FALSE, A_NONE);
-         break;
-       }
-      } tech_type_iterate_end;
-    }
+  int mod;
+
+  if ((mod = get_player_bonus(pplayer, EFT_TECH_PARASITE)) > 0) {
+    tech_type_iterate(i) {
+      if (get_invention(pplayer, i) != TECH_KNOWN
+         && tech_is_available(pplayer, i)
+         && game.global_advances[i] >= mod) {
+       notify_player_ex(pplayer, -1, -1, E_TECH_GAIN,
+           _("Game: %s acquired from a building!"),
+           advances[i].name);
+       gamelog(GAMELOG_TECH, _("%s discover %s (building)"),
+           get_nation_name_plural(pplayer->nation), advances[i].name);
+       notify_embassies(pplayer, NULL,
+           _("Game: The %s have acquired %s"
+             " from a building."),
+           get_nation_name_plural(pplayer->nation),
+           advances[i].name);
+
+       do_free_cost(pplayer);
+       found_new_tech(pplayer, i, FALSE, FALSE, A_NONE);
+       break;
+      }
+    } tech_type_iterate_end;
   }
 }
 
@@ -289,9 +287,13 @@
 {
   bool bonus_tech_hack = FALSE;
   bool was_first = FALSE;
-  bool macro_polo_was_obsolete = wonder_obsolete(B_MARCO);
+  int had_embassy[MAX_NUM_PLAYERS];
   struct city *pcity;
 
+  players_iterate(aplr) {
+    had_embassy[aplr->player_no] = get_player_bonus(aplr, EFT_HAVE_EMBASSIES);
+  } players_iterate_end;
+
   /* HACK: A_FUTURE doesn't "exist" and is thus not "available".  This may
    * or may not be the correct thing to do.  For these sanity checks we
    * just special-case it. */
@@ -453,17 +455,14 @@
    * Send all player an updated info of the owner of the Marco Polo
    * Wonder if this wonder has become obsolete.
    */
-  if (!macro_polo_was_obsolete && wonder_obsolete(B_MARCO)) {
-    struct city *pcity = find_city_wonder(B_MARCO);
-
-    if (pcity) {
-      struct player *owner = city_owner(pcity);
-
+  players_iterate(owner) {
+    if (had_embassy[owner->player_no]
+       && !get_player_bonus(owner, EFT_HAVE_EMBASSIES)) {
       players_iterate(other_player) {
        send_player_info(owner, other_player);
       } players_iterate_end;
     }
-  }
+  } players_iterate_end;
 
   /* Update Team */
   if (next_tech > A_NONE) {
@@ -933,7 +932,7 @@
 
   check_player_government_rates(pplayer);
   global_city_refresh(pplayer);
-  if (player_owns_active_govchange_wonder(pplayer)) {
+  if (get_player_bonus(pplayer, EFT_NO_ANARCHY)) {
     pplayer->revolution_finishes = game.turn;
   }
   send_player_info(pplayer, pplayer);
Index: server/plrhand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.h,v
retrieving revision 1.65
diff -u -r1.65 plrhand.h
--- server/plrhand.h    17 Jun 2004 19:50:41 -0000      1.65
+++ server/plrhand.h    1 Sep 2004 01:53:11 -0000
@@ -33,7 +33,7 @@
 void kill_player(struct player *pplayer);
 void kill_dying_players(void);
 void update_revolution(struct player *pplayer);
-void great_library(struct player *pplayer);
+void do_tech_parasite_effect(struct player *pplayer);
 void check_player_government_rates(struct player *pplayer);
 void make_contact(struct player *pplayer1, struct player *pplayer2, int x,
                  int y);
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.192
diff -u -r1.192 ruleset.c
--- server/ruleset.c    31 Aug 2004 04:40:50 -0000      1.192
+++ server/ruleset.c    1 Sep 2004 01:53:11 -0000
@@ -1138,12 +1138,7 @@
            nval, B_LAST, filename);
     exit(EXIT_FAILURE);
   }
-  /* FIXME: Remove this restriction when gen-impr implemented. */
-  if (nval != B_LAST_ENUM) {
-    freelog(LOG_FATAL, "Bad number of buildings %d (%s)", nval, filename);
-    exit(EXIT_FAILURE);
-  }
-  /* REMOVE TO HERE when gen-impr implemented. */
+
   game.num_impr_types = nval;
 
   impr_type_iterate(i) {
@@ -1152,6 +1147,8 @@
     improvement_types[i].name_orig[0] = 0;
   } impr_type_iterate_end;
 
+  ruleset_cache_init();
+
   free(sec);
 }
 
@@ -1162,13 +1159,56 @@
 {
   char **sec, *item, **list;
   int i, j, k, nval, count;
-  bool problem;
   struct impr_type *b;
-  struct impr_effect *e;
   const char *filename = secfile_filename(file);
 
   (void) check_ruleset_capabilities(file, "+1.10.1", filename);
 
+  /* Parse effect equivalence effect building groups. */
+  sec = secfile_get_secnames_prefix(file, "group_", &nval);
+  for (i = 0; i < nval; i++) {
+    struct eff_group *group;
+    char name[MAX_LEN_NAME];
+
+    item = secfile_lookup_str(file, "%s.name", sec[i]);
+    sz_strlcpy(name, item);
+
+    group = eff_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 effect_range range;
+      bool survives;
+
+      if ((id = find_improvement_by_name(item)) == B_LAST) {
+       freelog(LOG_ERROR, "for %s unknown improvement: \"%s\" (%s)",
+               name, item, filename);
+       continue;
+      }
+
+      item = secfile_lookup_str_default(file, NULL, "%s.elements%d.range",
+                                       sec[i], j);
+      if (item) {
+       if ((range = effect_range_from_str(item)) == EFR_LAST) {
+         freelog(LOG_ERROR, "for %s bad range: \"%s\" (%s)",
+                 name, item, filename);
+         continue;
+       }
+      } else {
+       range = EFR_CITY;
+      }
+
+      survives = secfile_lookup_bool_default(file, FALSE, 
"%s.elements%d.survives",
+                                            sec[i], j);
+
+      eff_group_add(group, id, range, survives);
+    }
+  }
+  free(sec);
+
   sec = secfile_get_secnames_prefix(file, "building_", &nval);
 
   for (i = 0; i < nval; i++) {
@@ -1263,6 +1303,9 @@
       b->obsolete_by = A_LAST;
     }
 
+    b->replaced_by = lookup_impr_type(file, sec[i], "replaced_by",
+                                     FALSE, filename, b->name);
+
     b->is_wonder = secfile_lookup_bool(file, "%s.is_wonder", sec[i]);
 
     b->build_cost = secfile_lookup_int(file, "%s.build_cost", sec[i]);
@@ -1271,164 +1314,82 @@
 
     b->sabotage = secfile_lookup_int(file, "%s.sabotage", sec[i]);
 
-    for (count = 0;
-        secfile_lookup_str_default(file, NULL, "%s.effect%d.type", sec[i],
-                                   count); count++) {
-      /* nothing */
-    }
-
-    if (count>MAX_EFFECTS) {
-      freelog(LOG_FATAL, "For %s maximum number of effects (%d) exceeded",
-              b->name, MAX_EFFECTS);
-      exit(EXIT_FAILURE);
-    }
-
-    b->effect = fc_malloc((count + 1) * sizeof(b->effect[0]));
-    k = 0;
-    for (j = 0; j < count; j++) {
-      e = &b->effect[k];
-      problem = FALSE;
-
-      item = secfile_lookup_str(file, "%s.effect%d.type", sec[i], j);
-      e->type = effect_type_from_str(item);
-      if (e->type == EFT_LAST) {
-       freelog(LOG_ERROR,
-               "for %s effect[%d].type couldn't match type \"%s\" (%s)",
-               b->name, j, item, filename);
-       problem = TRUE;
-      }
-
-      item =
-       secfile_lookup_str_default(file, "None", "%s.effect%d.range", sec[i], 
j);
-      e->range = effect_range_from_str(item);
-      if (e->range == EFR_LAST) {
-       freelog(LOG_ERROR,
-               "for %s effect[%d].range couldn't match range \"%s\" (%s)",
-               b->name, j, item, filename);
-       problem = TRUE;
-      }
-
-      e->amount =
-       secfile_lookup_int_default(file, 0, "%s.effect%d.amount", sec[i], j);
-
-      e->survives =
-       secfile_lookup_int_default(file, 0, "%s.effect%d.survives", sec[i], j);
-
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", sec[i], 
j);
-      if (*item != '\0') {
-       e->cond_bldg = find_improvement_by_name(item);
-       if (e->cond_bldg == B_LAST) {
-         freelog(LOG_ERROR,
-                 "for %s effect[%d].cond_bldg couldn't match improvement 
\"%s\" (%s)",
-                 b->name, j, item, filename);
-         problem = TRUE;
+    /* Parse building effects and add them to the effects hash. */
+    {
+      for (j = 0;
+         (item = secfile_lookup_str_default(file, NULL, "%s.effect%d.eff",
+                                           sec[i], j));
+         j++) {
+       int value;
+       enum effect_type eff;
+       enum effect_range range;
+       bool survives;
+       enum req_type type;
+       int req, equiv;
+
+       if ((eff = effect_type_from_str(item)) == EFT_LAST) {
+         freelog(LOG_ERROR, "for %s unknown effect type: \"%s\" (%s)",
+                 b->name, item, filename);
+         continue;
        }
-      } else {
-       e->cond_bldg = B_LAST;
-      }
 
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", sec[i], j);
-      if (*item != '\0') {
-       struct government *g = find_government_by_name(item);
-       if (!g) {
-         freelog(LOG_ERROR,
-                 "for %s effect[%d].cond_gov couldn't match government \"%s\" 
(%s)",
-                 b->name, j, item, filename);
-         e->cond_gov = game.government_count;
-         problem = TRUE;
+       item = secfile_lookup_str_default(file, "", "%s.effect%d.range",
+                                         sec[i], j);
+       if (*item != '\0') {
+         if ((range = effect_range_from_str(item)) == EFR_LAST) {
+           freelog(LOG_ERROR, "for %s bad range: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
+         }
        } else {
-         e->cond_gov = g->index;
+         range = EFR_CITY;
        }
-      } else {
-       e->cond_gov = game.government_count;
-      }
 
-      item =
-       secfile_lookup_str_default(file, "None", "%s.effect%d.cond_adv", 
sec[i], j);
-      if (*item != '\0') {
-       e->cond_adv = find_tech_by_name(item);
-       if (e->cond_adv == A_LAST) {
-         freelog(LOG_ERROR,
-                 "for %s effect[%d].cond_adv couldn't match tech \"%s\" (%s)",
-                 b->name, j, item, filename);
-         problem = TRUE;
-       }
-      } else {
-       e->cond_adv = A_NONE;
-      }
+       survives = secfile_lookup_bool_default(file, FALSE, 
"%s.effect%d.survives",
+                                              sec[i], j);
 
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", sec[i], j);
-      if (*item != '\0') {
-       e->cond_eff = effect_type_from_str(item);
-       if (e->cond_eff == EFT_LAST) {
-         freelog(LOG_ERROR,
-                 "for %s effect[%d].cond_eff couldn't match effect \"%s\" 
(%s)",
-                 b->name, j, item, filename);
-         problem = TRUE;
-       }
-      } else {
-       e->cond_eff = EFT_LAST;
-      }
+       value = secfile_lookup_int_default(file, 1, "%s.effect%d.value",
+                                          sec[i], j);
 
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", sec[i], j);
-      if (*item != '\0') {
-       e->aff_unit = unit_class_from_str(item);
-       if (e->aff_unit == UCL_LAST) {
-         freelog(LOG_ERROR,
-                 "for %s effect[%d].aff_unit couldn't match class \"%s\" (%s)",
-                 b->name, j, item, filename);
-         problem = TRUE;
-       }
-      } else {
-       e->aff_unit = UCL_LAST;
-      }
-
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", sec[i], j);
-      if (*item != '\0') {
-       if (0 == strcmp("None", item)) {
-         e->aff_terr = T_NONE;
-       } else {
-         e->aff_terr = get_terrain_by_name(item);
-         if (e->aff_terr == T_UNKNOWN) {
-           freelog(LOG_ERROR,
-                   "for %s effect[%d].aff_terr couldn't match terrain \"%s\" 
(%s)",
-                   b->name, j, item, filename);
-           e->aff_terr = T_NONE;
-           problem = TRUE;
+       item = secfile_lookup_str_default(file, "", "%s.effect%d.equiv",
+                                         sec[i], j);
+       if (*item != '\0') {
+         if ((equiv = find_eff_group(item)) == -1) {
+           freelog(LOG_ERROR, "for %s bad effect group: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
          }
+       } else {
+         equiv = -1;
        }
-      } else {
-       e->aff_terr = T_UNKNOWN;
-      }
 
-      item =
-       secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", sec[i], j);
-      if (*item != '\0') {
-       if (0 == strcmp("None", item)) {
-         e->aff_spec = S_NO_SPECIAL;
-       } else {
-         e->aff_spec = get_special_by_name(item);
-         if (e->aff_spec == S_NO_SPECIAL) {
-           freelog(LOG_ERROR,
-                   "for %s effect[%d].aff_spec couldn't match special \"%s\" 
(%s)",
-                   b->name, j, item, filename);
-           problem = TRUE;
+       item = secfile_lookup_str_default(file, "", "%s.effect%d.req_type",
+                                         sec[i], j);
+       if (*item != '\0') {
+         if ((type = req_type_from_str(item)) == REQ_LAST) {
+           freelog(LOG_ERROR, "for %s unknown requirement type: \"%s\" (%s)",
+                   b->name, item, filename);
+           continue;
+          }
+
+         item = secfile_lookup_str_default(file, NULL, "%s.effect%d.req",
+                                           sec[i], j);
+
+         if (!item) {
+           freelog(LOG_ERROR, "for %s missing requirement data (%s)",
+               b->name, filename);
+           continue;
+         } else {
+           req = parse_req(i, type, item);
          }
-       }
-      } else {
-       e->aff_spec = S_ALL;
-      }
+        } else {
+          type = REQ_NONE;
+          req = 0;
+        }
 
-      if (!problem) {
-       k++;
+       ruleset_cache_add(i, eff, range, survives, value, type, req, equiv);
       }
     }
-    b->effect[k].type = EFT_LAST;
 
     /* FIXME: remove when gen-impr obsoletes */
     b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]);
@@ -1446,6 +1407,20 @@
     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, "Cannot find any palace building");
+  }
+
+  game.land_defend_building = get_building_for_effect(EFT_LAND_DEFEND);
+  if (game.land_defend_building == B_LAST) {
+    freelog(LOG_FATAL, "Cannot find any land defend building");
+  }
+
   /* Some more consistency checking: */
   impr_type_iterate(i) {
     b = &improvement_types[i];
@@ -1463,21 +1438,24 @@
                b->name, advances[b->obsolete_by].name, filename);
        b->obsolete_by = A_LAST;
       }
-      for (j = 0; b->effect[j].type != EFT_LAST; j++) {
-       if (!tech_exists(b->effect[j].cond_adv)) {
-         freelog(LOG_ERROR,
-                 "improvement \"%s\": effect conditional on"
-                 " removed tech \"%s\" (%s)",
-                 b->name, advances[b->effect[j].cond_adv].name, filename);
-         b->effect[j].cond_adv = A_LAST;
-       }
-      }
     }
   } impr_type_iterate_end;
 
+  game.aqueduct_size = secfile_lookup_int(file, "b_special.aqueduct_size");
+
+  item = secfile_lookup_str(file, "b_special.default");
+  if (*item != '\0') {
+    game.default_building = find_improvement_by_name(item);
+    if (game.default_building == B_LAST) {
+      freelog(LOG_ERROR, "Bad value \"%s\" for b_special.default (%s)",
+             item, filename);
+    }
+  } else {
+    game.default_building = B_LAST;
+  }
+
   /* FIXME: remove all of the following when gen-impr implemented... */
 
-  game.aqueduct_size = secfile_lookup_int(file, "b_special.aqueduct_size");
   game.sewer_size = secfile_lookup_int(file, "b_special.sewer_size");
   
   game.rtech.cathedral_plus =
@@ -2004,6 +1982,8 @@
     sz_strlcpy(packet.team_name[i], team_get_by_id(i)->name);
   }
 
+  packet.default_building = game.default_building;
+
   lsend_packet_ruleset_control(dest, &packet);
 }
 
@@ -2390,6 +2370,11 @@
     lookup_building_list(file, sec[i], "init_buildings", pl->init_buildings,
                         filename);
 
+    /* Load nation specific initial buildings */
+
+    lookup_building_list(file, sec[i], "init_buildings", pl->init_buildings,
+                        filename);
+
     /* AI techs */
 
     techs = secfile_lookup_str_vec(file, &dim, "%s.tech_goals", sec[i]);
@@ -2763,6 +2748,12 @@
   lookup_building_list(&file, "options", "global_init_buildings",
                       game.rgame.global_init_buildings, filename);
 
+  /*
+   * Load global initial buildings
+   */
+  lookup_building_list(&file, "options", "global_init_buildings",
+                      game.rgame.global_init_buildings, filename);
+
   /* Enable/Disable killstack */
   game.rgame.killstack = secfile_lookup_bool(&file, "combat_rules.killstack");
        
@@ -2869,7 +2860,6 @@
   impr_type_iterate(i) {
     struct impr_type *b = &improvement_types[i];
     struct packet_ruleset_building packet;
-    struct impr_effect *eff;
 
     packet.id = i;
     sz_strlcpy(packet.name, b->name_orig);
@@ -2879,6 +2869,7 @@
     packet.bldg_req = b->bldg_req;
     packet.equiv_range = b->equiv_range;
     packet.obsolete_by = b->obsolete_by;
+    packet.replaced_by = b->replaced_by;
     packet.is_wonder = b->is_wonder;
     packet.build_cost = b->build_cost;
     packet.upkeep = b->upkeep;
@@ -2904,12 +2895,6 @@
     T(equiv_repl, equiv_repl_count, B_LAST);
 #undef T
 
-    packet.effect_count = 0;
-    for (eff = b->effect; eff->type != EFT_LAST; eff++) {
-      packet.effect[packet.effect_count] = *eff;
-      packet.effect_count++;
-    }
-
     lsend_packet_ruleset_building(dest, &packet);
   } impr_type_iterate_end;
 }
@@ -3105,7 +3090,8 @@
       packet.leader_sex[i] = n->leaders[i].is_male;
     }
     packet.city_style = n->city_style;
-    memcpy(packet.init_techs, n->init_techs, sizeof(packet.init_techs));
+    memcpy(packet.init_techs, n->init_techs,
+          sizeof(packet.init_techs));
     sz_strlcpy(packet.class, n->class);
     sz_strlcpy(packet.legend, n->legend);
 
@@ -3251,6 +3237,9 @@
   send_ruleset_nations(dest);
   send_ruleset_cities(dest);
 
+  send_ruleset_cache(dest);
+
   lsend_packet_thaw_hint(dest);
   conn_list_do_unbuffer(dest);
 }
+
Index: server/score.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/score.c,v
retrieving revision 1.5
diff -u -r1.5 score.c
--- server/score.c      27 May 2004 22:14:19 -0000      1.5
+++ server/score.c      1 Sep 2004 01:53:11 -0000
@@ -408,6 +408,8 @@
   }
 
   city_list_iterate(pplayer->cities, pcity) {
+    int bonus;
+
     pplayer->score.happy += pcity->ppl_happy[4];
     pplayer->score.content += pcity->ppl_content[4];
     pplayer->score.unhappy += pcity->ppl_unhappy[4];
@@ -421,11 +423,9 @@
     pplayer->score.techout += pcity->science_total;
     pplayer->score.bnp += pcity->trade_prod;
     pplayer->score.mfg += pcity->shield_surplus;
-    if (city_got_building(pcity, B_UNIVERSITY)) {
-      pplayer->score.literacy += city_population(pcity);
-    } else if (city_got_building(pcity,B_LIBRARY)) {
-      pplayer->score.literacy += city_population(pcity) / 2;
-    }
+
+    bonus = CLIP(0, get_city_bonus(pcity, EFT_SCIENCE_BONUS), 100);
+    pplayer->score.literacy += (city_population(pcity) * bonus) / 100;
   } city_list_iterate_end;
 
   if (pplayer->player_no == 0) {
Index: server/settlers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v
retrieving revision 1.199
diff -u -r1.199 settlers.c
--- server/settlers.c   31 Aug 2004 04:40:51 -0000      1.199
+++ server/settlers.c   1 Sep 2004 01:53:11 -0000
@@ -885,7 +885,7 @@
 
     assert(pcity != NULL);
     cost = city_granary_size(pcity->size);
-    if (city_got_effect(pcity, B_GRANARY)) { cost /= 2; }
+    if (get_city_bonus(pcity, EFT_GROWTH_FOOD)) { cost /= 2; }
   }
 
   return cost;
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.184
diff -u -r1.184 srv_main.c
--- server/srv_main.c   29 Aug 2004 19:03:32 -0000      1.184
+++ server/srv_main.c   1 Sep 2004 01:53:12 -0000
@@ -307,40 +307,37 @@
 /**************************************************************************
 ...
 **************************************************************************/
-static void do_apollo_program(void)
+static void do_reveal_effects(void)
 {
-  struct city *pcity = find_city_wonder(B_APOLLO);
-
-  if (pcity) {
-    struct player *pplayer = city_owner(pcity);
-
-    if (game.civstyle == 1) {
-      players_iterate(other_player) {
-       city_list_iterate(other_player->cities, pcity) {
+  players_iterate(pplayer) {
+    if (get_player_bonus(pplayer, EFT_REVEAL_CITIES)) {
+      players_iterate(pother) {
+       city_list_iterate(pother->cities, pcity) {
          show_area(pplayer, pcity->x, pcity->y, 0);
        } city_list_iterate_end;
       } players_iterate_end;
-    } else {
+    }
+    if (get_player_bonus(pplayer, EFT_REVEAL_MAP)) {
       /* map_know_all will mark all unknown tiles as known and send
        * tile, unit, and city updates as necessary.  No other actions are
        * needed. */
       map_know_all(pplayer);
     }
-  }
+  } players_iterate_end;
 }
 
 /**************************************************************************
 ...
 **************************************************************************/
-static void marco_polo_make_contact(void)
+static void do_have_embassies_effect(void)
 {
-  struct city *pcity = find_city_wonder(B_MARCO);
-
-  if (pcity) {
-    players_iterate(pplayer) {
-      make_contact(city_owner(pcity), pplayer, pcity->x, pcity->y);
-    } players_iterate_end;
-  }
+  players_iterate(pplayer) {
+    if (get_player_bonus(pplayer, EFT_HAVE_EMBASSIES)) {
+      players_iterate(pother) {
+       make_contact(pplayer, pother, -1, -1);
+      } players_iterate_end;
+    }
+  } players_iterate_end;
 }
 
 /**************************************************************************
@@ -556,7 +553,7 @@
 
   /* Refresh cities */
   shuffled_players_iterate(pplayer) {
-    great_library(pplayer);
+    do_tech_parasite_effect(pplayer);
     player_restore_units(pplayer);
     update_city_activities(pplayer);
     pplayer->research.changed_from=-1;
@@ -573,8 +570,8 @@
   } players_iterate_end;
   flush_packets();  /* to curb major city spam */
 
-  do_apollo_program();
-  marco_polo_make_contact();
+  do_reveal_effects();
+  do_have_embassies_effect();
 
   freelog(LOG_DEBUG, "Auto-Attack phase");
   auto_attack();
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.303
diff -u -r1.303 unithand.c
--- server/unithand.c   26 Aug 2004 18:37:52 -0000      1.303
+++ server/unithand.c   1 Sep 2004 01:53:12 -0000
@@ -443,17 +443,11 @@
                     _("Game: %s is too big to add %s."),
                     pcity->name, unit_name);
     break;
-  case AB_NO_AQUEDUCT:
+  case AB_NO_SPACE:
     notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
-                    _("Game: %s needs %s to grow, so you cannot add %s."),
-                    pcity->name, get_improvement_name(B_AQUEDUCT),
-                    unit_name);
-    break;
-  case AB_NO_SEWER:
-    notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
-                    _("Game: %s needs %s to grow, so you cannot add %s."),
-                    pcity->name, get_improvement_name(B_SEWER),
-                    unit_name);
+                    _("Game: %s needs an improvement to grow, so "
+                      "you cannot add %s."),
+                    pcity->name, unit_name);
     break;
   default:
     /* Shouldn't happen */
@@ -715,7 +709,7 @@
   
   if (pcity
       && pcity->size > 1
-      && !city_got_citywalls(pcity)
+      && !get_city_bonus(pcity, EFT_UNIT_NO_LOSE_POP)
       && kills_citizen_after_attack(punit)) {
     city_reduce_size(pcity,1);
     city_refresh(pcity);
@@ -814,7 +808,7 @@
   if (punit->hp &&
       (pcity=map_get_city(def_x, def_y)) &&
       pcity->size>1 &&
-      !city_got_citywalls(pcity) &&
+      !get_city_bonus(pcity, EFT_UNIT_NO_LOSE_POP) &&
       kills_citizen_after_attack(punit)) {
     city_reduce_size(pcity,1);
     city_refresh(pcity);
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.300
diff -u -r1.300 unittools.c
--- server/unittools.c  26 Aug 2004 18:37:53 -0000      1.300
+++ server/unittools.c  1 Sep 2004 01:53:13 -0000
@@ -60,7 +60,7 @@
 static void unit_restore_movepoints(struct player *pplayer, struct unit 
*punit);
 static void update_unit_activity(struct unit *punit);
 static void wakeup_neighbor_sentries(struct unit *punit);
-static void handle_leonardo(struct player *pplayer);
+static void do_upgrade_effects(struct player *pplayer);
 
 static void sentry_transported_idle_units(struct unit *ptrans);
 
@@ -116,21 +116,22 @@
       || unit_type(punit)->veteran[punit->veteran].name[0] == '\0'
       || unit_flag(punit, F_NO_VETERAN)) {
     return FALSE;
-  }
-  if (is_ground_unittype(punit->type)
-      && player_owns_active_wonder(get_player(punit->owner), B_SUNTZU)) {
-    if (myrand(100) < 1.5 * game.veteran_chance[punit->veteran]) {
-      punit->veteran++;
-      return TRUE;
-    }
   } else {
-    if (myrand(100) < game.veteran_chance[punit->veteran]) {
+    struct player *plr;
+    double mod = 1.0;
+
+    plr = get_player(punit->owner);
+
+    if (is_ground_unittype(punit->type)) {
+      mod += (0.01 * get_player_bonus(plr, EFT_LAND_VET_COMBAT));
+    }
+
+    if (myrand(100) < (mod * game.veteran_chance[punit->veteran])) {
       punit->veteran++;
       return TRUE;
     }
+    return FALSE;
   }
-
-  return FALSE;  
 }
 
 /**************************************************************************
@@ -197,50 +198,54 @@
 Do Leonardo's Workshop upgrade(s). Select unit to upgrade by random. --Zamar
 Now be careful not to strand units at sea with the Workshop. --dwp
 ****************************************************************************/
-static void handle_leonardo(struct player *pplayer)
+static void do_upgrade_effects(struct player *pplayer)
 {
-  int leonardo_variant;
-       
-  struct unit_list candidates;
-  int candidate_to_upgrade=-1;
-
-  int i;
-
-  leonardo_variant = improvement_variant(B_LEONARDO);
-       
-  unit_list_init(&candidates);
-       
-  unit_list_iterate(pplayer->units, punit) {
-    if (test_unit_upgrade(punit, TRUE) == UR_OK) {
-      unit_list_insert(&candidates, punit);    /* Potential candidate :) */
-    }
-  } unit_list_iterate_end;
-       
-  if (unit_list_size(&candidates) == 0)
-    return; /* We have Leonardo, but nothing to upgrade! */
-       
-  if (leonardo_variant == 0)
-    candidate_to_upgrade=myrand(unit_list_size(&candidates));
-
-  i=0; 
-  unit_list_iterate(candidates, punit) {
-    if (leonardo_variant != 0 || i == candidate_to_upgrade) {
-      Unit_Type_id upgrade_type = can_upgrade_unittype(pplayer, punit->type);
-
-      notify_player(pplayer,
-            _("Game: %s has upgraded %s to %s%s."),
-            improvement_types[B_LEONARDO].name,
-            unit_type(punit)->name,
-            get_unit_type(upgrade_type)->name,
-            get_location_str_in(pplayer, punit->x, punit->y));
-      punit->veteran = 0;
-      assert(test_unit_upgrade(punit, TRUE) == UR_OK);
-      upgrade_unit(punit, upgrade_type, TRUE);
-    }
-    i++;
-  } unit_list_iterate_end;
-       
-  unit_list_unlink_all(&candidates);
+  bool one_leap = FALSE, all_leap = FALSE;
+
+  all_leap = get_player_bonus(pplayer, EFT_UPGRADE_ALL_LEAP);
+  if (!all_leap) {
+    one_leap = get_player_bonus(pplayer, EFT_UPGRADE_ONE_LEAP);
+  }
+
+  if (one_leap || all_leap) {
+    struct unit_list candidates;
+    int candidate_to_upgrade=-1;
+
+    int i;
+
+    unit_list_init(&candidates);
+
+    unit_list_iterate(pplayer->units, punit) {
+      if (test_unit_upgrade(punit, TRUE) == UR_OK) {
+       unit_list_insert(&candidates, punit);   /* Potential candidate :) */
+      }
+    } unit_list_iterate_end;
+
+    if (unit_list_size(&candidates) == 0)
+      return; /* We have Leonardo, but nothing to upgrade! */
+
+    if (one_leap)
+      candidate_to_upgrade=myrand(unit_list_size(&candidates));
+
+    i=0;       
+    unit_list_iterate(candidates, punit) {
+      if (all_leap || i == candidate_to_upgrade) {
+       Unit_Type_id upgrade_type = can_upgrade_unittype(pplayer, punit->type);
+
+       notify_player(pplayer,
+           _("Game: %s was upgraded for free to %s%s."),
+           unit_type(punit)->name,
+           get_unit_type(upgrade_type)->name,
+           get_location_str_in(pplayer, punit->x, punit->y));
+       punit->veteran = 0;
+       assert(test_unit_upgrade(punit, TRUE) == UR_OK);
+       upgrade_unit(punit, upgrade_type, TRUE);
+      }
+      i++;
+    } unit_list_iterate_end;
+
+    unit_list_unlink_all(&candidates);
+  }
 }
 
 /***************************************************************************
@@ -294,8 +299,7 @@
 void player_restore_units(struct player *pplayer)
 {
   /* 1) get Leonardo out of the way first: */
-  if (player_owns_active_wonder(pplayer, B_LEONARDO))
-    handle_leonardo(pplayer);
+  do_upgrade_effects(pplayer);
 
   unit_list_iterate_safe(pplayer->units, punit) {
 
@@ -430,9 +434,8 @@
     punit->hp+=hp_gain_coord(punit);
   }
   
-  if (player_owns_active_wonder(pplayer, B_UNITED)) 
-    punit->hp+=2;
-    
+  punit->hp += get_player_bonus(pplayer, EFT_UNIT_RECOVER);
+
   if(is_heli_unit(punit)) {
     struct city *pcity = map_get_city(punit->x,punit->y);
     if(!pcity) {
@@ -492,11 +495,9 @@
   else
     hp=0;
   if((pcity=map_get_city(punit->x,punit->y))) {
-    if ((city_got_barracks(pcity) &&
-        (is_ground_unit(punit) || improvement_variant(B_BARRACKS)==1)) ||
-       (city_got_building(pcity, B_AIRPORT) && is_air_unit(punit)) || 
-       (city_got_building(pcity, B_AIRPORT) && is_heli_unit(punit)) || 
-       (city_got_building(pcity, B_PORT) && is_sailing_unit(punit))) {
+    if ((get_city_bonus(pcity, EFT_LAND_REGEN) && is_ground_unit(punit)) ||
+       (get_city_bonus(pcity, EFT_AIR_REGEN) && (is_air_unit(punit) || 
is_heli_unit(punit))) || 
+       (get_city_bonus(pcity, EFT_SEA_REGEN) && is_sailing_unit(punit))) {
       hp=unit_type(punit)->hp;
     }
     else

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