diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/packhand.c freeciv-patched/client/packhand.c
--- freeciv-cvs/client/packhand.c	2002-12-06 19:52:05.000000000 +0000
+++ freeciv-patched/client/packhand.c	2002-12-06 19:52:07.000000000 +0000
@@ -490,6 +490,8 @@
            pcity->owner==game.player_idx && popup_new_cities) 
           || packet->diplomat_investigate;
 
+  try_update_effects(need_effect_update);
+
   if (city_is_new && !city_has_changed_owner) {
     agents_city_new(pcity);
   } else {
@@ -497,8 +499,6 @@
   }
 
   handle_city_packet_common(pcity, city_is_new, popup, packet->diplomat_investigate);
-
-  try_update_effects(need_effect_update);
 }
 
 /**************************************************************************
@@ -681,6 +681,8 @@
 	pcity->city_map[x][y] = C_TILE_EMPTY;
   } /* Dumb values */
 
+  try_update_effects(need_effect_update);
+
   if (city_is_new && !city_has_changed_owner) {
     agents_city_new(pcity);
   } else {
@@ -693,8 +695,6 @@
   if (update_descriptions && tile_visible_mapcanvas(pcity->x,pcity->y)) {
     update_city_descriptions();
   }
-
-  try_update_effects(need_effect_update);
 }
 
 /**************************************************************************
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.c freeciv-patched/common/city.c
--- freeciv-cvs/common/city.c	2002-12-06 19:52:05.000000000 +0000
+++ freeciv-patched/common/city.c	2002-12-06 19:52:07.000000000 +0000
@@ -570,10 +570,14 @@
   }
   if (contains_special(spec_t, S_RAILROAD))
     s+=(s*terrain_control.rail_shield_bonus)/100;
-  if (city_affected_by_wonder(pcity, B_RICHARDS))
-    s++;
-  if (tile_t==T_OCEAN && city_got_building(pcity, B_OFFSHORE))
-    s++;
+
+  /* Add effects from generalised improvements */
+  s += pcity->tile_bonuses[x][y].shields;
+  if (s > 0) {
+    s += pcity->tile_add[x][y].shields;
+  }
+  s = s * pcity->tile_pct[x][y].shields / 100;
+
   /* government shield bonus & penalty */
   if (s > 0)
     s += (is_celebrating ? g->celeb_shield_bonus : g->shield_bonus);
@@ -663,6 +667,15 @@
   if (contains_special(spec_t, S_ROAD)) {
     t += (get_tile_type(tile_t))->road_trade_incr;
   }
+
+  /* Add effects from generalised improvements */
+  t += pcity->tile_bonuses[x][y].trade;
+  if (t > 0) {
+    t += pcity->tile_add[x][y].trade;
+  }
+  if (t < 0) t = 0;  /* Don't want tiles producing negative trade */
+  t = t * pcity->tile_pct[x][y].trade / 100;
+
   if (t > 0) {
     int before_penalty = (is_celebrating ? g->celeb_trade_before_penalty
 			  : g->trade_before_penalty);
@@ -675,11 +688,6 @@
     if (t > 0)
       t += (is_celebrating ? g->celeb_trade_bonus : g->trade_bonus);
 
-    if(city_affected_by_wonder(pcity, B_COLLOSSUS)) 
-      t++;
-    if(contains_special(spec_t, S_ROAD) && city_got_building(pcity, B_SUPERHIGHWAYS))
-      t+=(t*terrain_control.road_superhighway_trade_bonus)/100;
- 
     /* government trade penalty -- SKi */
     if (before_penalty > 0 && t > before_penalty) 
       t--;
@@ -774,16 +782,14 @@
 
   if (contains_special(spec_t, S_IRRIGATION) || city_auto_water) {
     f += type->irrigation_food_incr;
-    if ((contains_special(spec_t, S_FARMLAND) ||
-	 (city_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;
-    }
   }
 
-  if (tile_t==T_OCEAN && city_got_building(pcity, B_HARBOUR))
-    f++;
+  /* Add effects from generalised improvements */
+  f += pcity->tile_bonuses[x][y].food;
+  if (f > 0) {
+    f += pcity->tile_add[x][y].food;
+  }
+  f = f * pcity->tile_pct[x][y].food / 100;
 
   if (contains_special(spec_t, S_RAILROAD))
     f+=(f*terrain_control.rail_food_bonus)/100;
@@ -1572,6 +1578,80 @@
 }
 
 /**************************************************************************
+  Sets the given city's shield/food/trade per-tile bonuses to defaults
+**************************************************************************/
+void city_init_tile_mods(struct city *pcity)
+{
+  struct tile_mod *tilept;
+
+  city_map_iterate(x, y) {
+    tilept = &pcity->tile_bonuses[x][y];
+    tilept->trade = tilept->shields = tilept->food = 0;
+
+    tilept = &pcity->tile_add[x][y];
+    tilept->trade = tilept->shields = tilept->food = 0;
+
+    tilept = &pcity->tile_pct[x][y];
+    tilept->trade = tilept->shields = tilept->food = 100;
+  } city_map_iterate_end;
+}
+
+static int handle_tile_bonuses(
+               struct impr_effect *imeff,
+               struct tile_mod add[CITY_MAP_SIZE][CITY_MAP_SIZE],
+               struct tile_mod bonus[CITY_MAP_SIZE][CITY_MAP_SIZE],
+               struct tile_mod pct[CITY_MAP_SIZE][CITY_MAP_SIZE],
+               enum tile_special_type tile_spec[CITY_MAP_SIZE][CITY_MAP_SIZE],
+               enum tile_terrain_type tile_terr[CITY_MAP_SIZE][CITY_MAP_SIZE])
+{
+  int amount;
+
+  amount = imeff->amount;
+
+  switch(imeff->type) {
+  case EFT_TRADE_ADD_TILE:
+  case EFT_TRADE_INC_TILE:
+  case EFT_TRADE_PER_TILE:
+  case EFT_PROD_ADD_TILE:
+  case EFT_PROD_INC_TILE:
+  case EFT_PROD_PER_TILE:
+  case EFT_FOOD_ADD_TILE:
+  case EFT_FOOD_INC_TILE:
+  case EFT_FOOD_PER_TILE:
+    city_map_iterate(x, y) {
+      if (is_unit_terrain_affected(imeff, UCL_LAST, tile_terr[x][y],
+                                   tile_spec[x][y])) {
+        switch(imeff->type) {
+        case EFT_TRADE_ADD_TILE:
+          add[x][y].trade += amount; break;
+        case EFT_TRADE_INC_TILE:
+          bonus[x][y].trade += amount; break;
+        case EFT_TRADE_PER_TILE:
+          pct[x][y].trade = pct[x][y].trade * amount / 100; break;
+        case EFT_PROD_ADD_TILE:
+          add[x][y].shields += amount; break;
+        case EFT_PROD_INC_TILE:
+          bonus[x][y].shields += amount; break;
+        case EFT_PROD_PER_TILE:
+          pct[x][y].shields = pct[x][y].shields * amount / 100; break;
+        case EFT_FOOD_ADD_TILE:
+          add[x][y].food += amount; break;
+        case EFT_FOOD_INC_TILE:
+          bonus[x][y].food += amount; break;
+        case EFT_FOOD_PER_TILE:
+          pct[x][y].food = pct[x][y].food * amount / 100; break;
+        default:
+          break;
+        }
+      }
+    } city_map_iterate_end;
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
+/**************************************************************************
   Updates the various modifiers and bonuses due to city improvements
   (should be called whenever city effects change - i.e. by
   update_all_effects and friends)
@@ -1591,6 +1671,11 @@
   int makecontentpct = 100, forcecontentpct = 100;
   int makecontentmil = 0, makecontentmilper = 0;
 
+  enum tile_special_type spec = map_get_special(pcity->x, pcity->y);
+  enum tile_terrain_type terr = map_get_terrain(pcity->x, pcity->y);
+  enum tile_special_type tile_spec[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  enum tile_terrain_type tile_terr[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
   int amount;
   struct player *pplayer;
   struct government *gov;
@@ -1598,9 +1683,41 @@
   pplayer = city_owner(pcity);
   gov = get_gov_pcity(pcity);
 
-  city_effects_iterate(iter, pcity) {
-    amount = iter.imeff->amount;
-    switch(iter.imeff->type) {
+  city_init_tile_mods(pcity);
+
+  city_map_iterate(x, y) {
+    struct tile_type *type;
+    int map_x, map_y, is_real, city_auto_water;
+
+    is_real = city_map_to_map(&map_x, &map_y, pcity, x, y);
+    if (is_real) {
+      tile_spec[x][y] = map_get_special(map_x, map_y);
+      tile_terr[x][y] = map_get_terrain(map_x, map_y);
+    } else {
+      tile_spec[x][y] = S_ALL;
+      tile_terr[x][y] = T_UNKNOWN;
+    }
+
+    type = get_tile_type(tile_terr[x][y]);
+    city_auto_water = (is_city_center(x, y)
+                       && tile_terr[x][y] == type->irrigation_result
+                       && terrain_control.may_irrigate);
+    /* City centre counts as farmland if we have the necessary tech */
+    if (city_auto_water
+        && player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) {
+      tile_spec[x][y] |= S_FARMLAND;
+    }
+  } city_map_iterate_end;
+
+  /* Ignore terrain in the iteration, as it's the terrain of the city
+     center - we need to consider all city tiles too */
+  city_effects_iterate_full(iter, pcity, UCL_LAST, T_UNKNOWN, S_ALL) {
+    if (!handle_tile_bonuses(iter.imeff, pcity->tile_add,
+                             pcity->tile_bonuses, pcity->tile_pct,
+                             tile_spec, tile_terr)
+        && is_unit_terrain_affected(iter.imeff, UCL_LAST, terr, spec)) {
+      amount = iter.imeff->amount;
+      switch(iter.imeff->type) {
       case EFT_TAX_BONUS:
         tax_bonus += amount; break;
       case EFT_TAX_PCT:
@@ -1647,6 +1764,7 @@
         forcehappy += amount; break;
       default:
         break;
+      }
     }
   } city_effects_iterate_end;
 
diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/city.h freeciv-patched/common/city.h
--- freeciv-cvs/common/city.h	2002-12-06 19:52:05.000000000 +0000
+++ freeciv-patched/common/city.h	2002-12-06 19:52:07.000000000 +0000
@@ -219,6 +219,10 @@
   bool already_considered_for_diplomat;
 };
 
+struct tile_mod {
+  int trade, shields, food;
+};
+
 struct city {
   int id;
   int owner;
@@ -249,6 +253,11 @@
   int shield_bonus, tax_bonus, science_bonus; /* more CPU savings! */
   int tithes_bonus;
 
+  /* per tile production bonuses from city improvements */
+  struct tile_mod tile_bonuses[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  struct tile_mod tile_add[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  struct tile_mod tile_pct[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
   /* happiness modifiers from city improvements */
   int makecontent, makehappy, forcecontent, forcehappy;
   int makecontentmil, makecontentmilper;
@@ -463,6 +472,7 @@
 
 /* city update functions */
 void update_city_bonuses(struct city *pcity);
+void city_init_tile_mods(struct city *pcity);
 void generic_city_refresh(struct city *pcity,
 			  bool refresh_trade_route_cities);
 void adjust_city_free_cost(int *num_free, int *this_cost);
