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

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

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#2521) general effects framework
From: "Mike Kaufman" <kaufman@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 15 Mar 2004 08:43:57 -0800
Reply-to: rt@xxxxxxxxxxx

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

files attached...


<<< multipart/mixed; boundary="----------=_1079369036-12895-2": Unrecognized >>>
diff -Nur -Xcvs/diff_ignore snap/client/packhand.c snap-eff/client/packhand.c
--- snap/client/packhand.c      2004-02-27 23:37:18.000000000 -0600
+++ snap-eff/client/packhand.c  2004-03-05 20:40:54.000000000 -0600
@@ -1322,6 +1322,8 @@
   game.heating=pinfo->heating;
   game.nuclearwinter=pinfo->nuclearwinter;
   game.cooling=pinfo->cooling;
+  game.can_nuke = pinfo->can_nuke;
+  game.can_space = pinfo->can_space;
   if (!can_client_change_view()) {
     improvement_status_init(game.improvements,
                            ARRAY_SIZE(game.improvements));
@@ -1505,6 +1507,9 @@
   pplayer->gives_shared_vision = pinfo->gives_shared_vision;
   pplayer->city_style=pinfo->city_style;
 
+  pplayer->can_nuke = pinfo->can_nuke;
+  pplayer->can_space = pinfo->can_space;
+
   for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
     pplayer->diplstates[i].type =
       pinfo->diplstates[i].type;
diff -Nur -Xcvs/diff_ignore snap/common/game.c snap-eff/common/game.c
--- snap/common/game.c  2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/game.c      2004-03-05 20:40:54.000000000 -0600
@@ -256,6 +256,10 @@
 
   game.heating     = 0;
   game.cooling     = 0;
+
+  game.can_nuke    = FALSE;
+  game.can_space   = FALSE;
+
   sz_strlcpy(game.save_name, GAME_DEFAULT_SAVE_NAME);
   game.save_nturns=10;
 #ifdef HAVE_LIBZ
diff -Nur -Xcvs/diff_ignore snap/common/game.h snap-eff/common/game.h
--- snap/common/game.h  2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/game.h      2004-03-05 20:40:54.000000000 -0600
@@ -119,6 +119,9 @@
   int coolinglevel; /* If nuclearwinter is higher than this number there is
                       a chance of a cooling event. */
 
+  bool can_nuke;        /* bits to record the two effects which survive */
+  bool can_space;       /* their origin's destruction. */
+
   char save_name[MAX_LEN_NAME];
   int save_nturns;
   int save_compress_level;
diff -Nur -Xcvs/diff_ignore snap/common/packets.def snap-eff/common/packets.def
--- snap/common/packets.def     2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/packets.def 2004-03-05 20:40:54.000000000 -0600
@@ -340,7 +340,7 @@
   UINT8 civstyle;
   UINT8 diplomacy;
 
-  BOOL spacerace;
+  BOOL spacerace, can_nuke, can_space;
 
   UINT8 global_advances[A_LAST]; diff
   UINT16 global_wonders[B_LAST]; diff
@@ -550,6 +550,7 @@
   UINT8 barbarian_type;
   uint32(unsigned int) gives_shared_vision;
   BIT_STRING inventions[A_LAST+1];
+  BOOL can_nuke, can_space;
 end
 
 PACKET_PLAYER_TURN_DONE=40;cs
diff -Nur -Xcvs/diff_ignore snap/common/player.c snap-eff/common/player.c
--- snap/common/player.c        2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/player.c    2004-03-05 20:40:54.000000000 -0600
@@ -146,6 +146,9 @@
     }
   }
 
+  plr->can_nuke = FALSE;
+  plr->can_space = FALSE;
+
   plr->attribute_block.data = NULL;
   plr->attribute_block.length = 0;
   plr->debug = FALSE;
diff -Nur -Xcvs/diff_ignore snap/common/player.h snap-eff/common/player.h
--- snap/common/player.h        2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/player.h    2004-03-05 20:40:54.000000000 -0600
@@ -210,6 +210,9 @@
   Impr_Status *island_improv; /* improvements with equiv_range==Island, 
dimensioned to
                                 [map.num_continents][game.num_impr_types] */
 
+  bool can_nuke;        /* bits to record the two effects which survive */
+  bool can_space;       /* their origin's destruction. */
+
   struct {
     int length;
     void *data;
diff -Nur -Xcvs/diff_ignore snap/server/savegame.c snap-eff/server/savegame.c
--- snap/server/savegame.c      2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/savegame.c  2004-03-05 20:40:54.000000000 -0600
@@ -767,6 +767,11 @@
   plr->revolution=secfile_lookup_int_default(file, 0, "player%d.revolution",
                                              plrno);
 
+  plr->can_nuke = secfile_lookup_bool_default(file, FALSE,
+                                              "player%d.can_nuke", plrno);
+  plr->can_space = secfile_lookup_bool_default(file, FALSE,
+                                               "player%d.can_space", plrno);
+
   tech_type_iterate(i) {
     if (p[i] == '1') {
       set_invention(plr, i, TECH_KNOWN);
@@ -1452,6 +1457,8 @@
 
   secfile_insert_bool(file, plr->capital, "player%d.capital", plrno);
   secfile_insert_int(file, plr->revolution, "player%d.revolution", plrno);
+  secfile_insert_bool(file, plr->can_nuke, "player%d.can_nuke", plrno);
+  secfile_insert_bool(file, plr->can_space, "player%d.can_space", plrno);
 
   tech_type_iterate(tech_id) {
     invs[tech_id] = (get_invention(plr, tech_id) == TECH_KNOWN) ? '1' : '0';
@@ -1968,6 +1975,9 @@
     game.warminglevel  = secfile_lookup_int(file, "game.warminglevel");
     game.nuclearwinter = secfile_lookup_int_default(file, 0, 
"game.nuclearwinter");
     game.coolinglevel  = secfile_lookup_int_default(file, 8, 
"game.coolinglevel");
+    game.can_nuke = secfile_lookup_bool_default(file, FALSE, "game.can_nuke");
+    game.can_space = secfile_lookup_bool_default(file, FALSE, 
"game.can_space");
+
     game.notradesize   = secfile_lookup_int_default(file, 0, 
"game.notradesize");
     game.fulltradesize = secfile_lookup_int_default(file, 1, 
"game.fulltradesize");
     game.unhappysize   = secfile_lookup_int(file, "game.unhappysize");
@@ -2386,6 +2396,8 @@
   secfile_insert_int(file, game.warminglevel, "game.warminglevel");
   secfile_insert_int(file, game.nuclearwinter, "game.nuclearwinter");
   secfile_insert_int(file, game.coolinglevel, "game.coolinglevel");
+  secfile_insert_bool(file, game.can_nuke, "game.can_nuke");
+  secfile_insert_bool(file, game.can_space, "game.can_space");
   secfile_insert_int(file, game.notradesize, "game.notradesize");
   secfile_insert_int(file, game.fulltradesize, "game.fulltradesize");
   secfile_insert_int(file, game.unhappysize, "game.unhappysize");
diff -Nur -Xcvs/diff_ignore snap-pre/ai/aihand.c snap-eff/ai/aihand.c
--- snap-pre/ai/aihand.c        2003-09-21 20:18:36.000000000 -0500
+++ snap-eff/ai/aihand.c        2004-03-05 20:44:46.000000000 -0600
@@ -20,6 +20,7 @@
 #include <string.h>
 
 #include "city.h"
+#include "effects.h"
 #include "game.h"
 #include "government.h"
 #include "log.h"
@@ -198,6 +199,7 @@
       /* Ideally we should change tax rates here, but since
        * this is a rather big CPU operation, we'd rather not. */
       check_player_government_rates(pplayer);
+      /* effects_update_all(); FIXME: UNCOMMENT WHEN THIS IS READY -mck */
       city_list_iterate(pplayer->cities, acity) {
         generic_city_refresh(acity, TRUE, NULL);
         auto_arrange_workers(acity);
diff -Nur -Xcvs/diff_ignore snap-pre/client/climisc.c snap-eff/client/climisc.c
--- snap-pre/client/climisc.c   2004-02-27 23:37:18.000000000 -0600
+++ snap-eff/client/climisc.c   2004-03-05 20:44:46.000000000 -0600
@@ -32,6 +32,7 @@
 
 #include "city.h"
 #include "diptreaty.h"
+#include "effects.h"
 #include "fcintl.h"
 #include "game.h"
 #include "log.h"
@@ -56,6 +57,24 @@
 
 #include "climisc.h"
 
+
+/**************************************************************************
+  the server needs to do more on update. see gamehand.c
+**************************************************************************/
+void effects_update_all(void)
+{
+  effects_update_all_common();
+}
+
+/**************************************************************************
+ the server needs to more on delete. see gamehand.c
+**************************************************************************/
+void delete_effects(enum effect_class class, struct player *pplayer, 
+                    struct city *pcity, struct unit *punit, int id)
+{
+  delete_effects_common(class, pplayer, pcity, punit, id);
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
@@ -135,13 +154,15 @@
      and to handle the preservation of "destroyed" effects. */
   effect_update=FALSE;
 
+  effects_defer_update();
   built_impr_iterate(pcity, i) {
     effect_update = TRUE;
     city_remove_improvement(pcity, i);
   } built_impr_iterate_end;
+  effects_undefer_update();
 
   if (effect_update) {
-    /* nothing yet */
+    effects_update_all();
   }
 
   popdown_city_dialog(pcity);
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand.c 
snap-eff/client/packhand.c
--- snap-pre/client/packhand.c  2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/client/packhand.c  2004-03-05 20:44:46.000000000 -0600
@@ -25,6 +25,7 @@
 
 #include "capability.h"
 #include "capstr.h"
+#include "effects.h"
 #include "events.h"
 #include "fcintl.h"
 #include "game.h"
@@ -77,6 +78,80 @@
 static int *reports_thaw_requests = NULL;
 static int reports_thaw_requests_size = 0;
 
+
+#ifdef DEBUG
+/**************************************************************************
+ print out effect definition debugging info 
+**************************************************************************/
+static void print_effect_definitions(struct effect_defn_vector *vec, 
+                                     char *header)
+{
+  freelog(LOG_DEBUG, "%s", header);
+
+  effect_defn_vector_iterate(*vec, defn) {
+    char buf[1024], *ptr;
+    ptr = buf;
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " %d/%s",
+                defn->type, effect_type_name(defn->type));
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " range=%d/%s",
+                defn->range, effect_range_name(defn->range));
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " outside=%d", defn->outside);
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " amount=%d", defn->amount);
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " value1=%d", defn->value1);
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " value2=%d", defn->value2);
+    ptr = strchr(ptr, '\0');
+    freelog(LOG_DEBUG, "     %s", buf);
+    ptr = buf;
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_bldg=%d/%s",
+                defn->cond_bldg, (defn->cond_bldg == B_LAST) ?
+                "Uncond." : improvement_types[defn->cond_bldg].name);
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_nat=%d/%s",
+                defn->cond_nat, (defn->cond_nat == -1) ?
+                "Uncond." : get_nation_name(defn->cond_gov));
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_gov=%d/%s",
+                defn->cond_gov, (defn->cond_gov == game.government_count) ?
+                "Uncond." : get_government_name(defn->cond_gov));
+    ptr = strchr(ptr, '\0');
+    freelog(LOG_DEBUG, "     %s", buf);
+    ptr = buf;
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_adv=%d/%s",
+                defn->cond_adv, (defn->cond_adv == A_NONE) ?
+                "Uncond." : (defn->cond_adv == A_LAST) ?  "Never" : 
+                advances[defn->cond_adv].name);
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " cond_eff=%d/%s",
+                defn->cond_eff, (defn->cond_eff == EFT_LAST) ?
+                "Uncond." : effect_type_name(defn->cond_eff));
+    ptr = strchr(ptr, '\0');
+    freelog(LOG_DEBUG, "     %s", buf);
+    ptr = buf;
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_unit=%d/%s",
+                defn->aff_unit, (defn->aff_unit == UCL_LAST) ?
+                "All" : unit_class_name(defn->aff_unit));
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_terr=%d/%s",
+                defn->aff_terr, (defn->aff_terr == T_LAST) ?
+                "None" : (defn->aff_terr == T_UNKNOWN) ?
+                "All" : get_terrain_name(defn->aff_terr));
+    ptr = strchr(ptr, '\0');
+    my_snprintf(ptr, sizeof(buf)-(ptr-buf), " aff_spec=%04X/%s",
+                defn->aff_spec, (defn->aff_spec == 0) ?
+                "None" : (defn->aff_spec == S_ALL) ?
+                "All" : get_special_name(defn->aff_spec));
+    ptr = strchr(ptr, '\0');
+    freelog(LOG_DEBUG, "     %s", buf);
+    freelog(LOG_DEBUG, " ");
+  } effect_defn_vector_iterate_end;
+}
+#endif
+
 /**************************************************************************
   Unpackage the unit information into a newly allocated unit structure.
 **************************************************************************/
@@ -291,15 +366,21 @@
 /**************************************************************************
   Updates a city's list of improvements from packet data. "impr" identifies
   the improvement, and "have_impr" specifies whether the improvement should
-  be added (TRUE) or removed (FALSE). "impr_changed" is set TRUE only if
+  be added (TRUE) or removed (FALSE). "impr_changed" is set TRUE only if 
   the existing improvement status was changed by this call.
-**************************************************************************/
+
+  Don't add immediate effects here, since we're only reporting to the client
+  what others have built. TODO: this may not be the best way to do this.
+  The client may want info on what effects had occurred in the past, but
+  will not get it this way. For example, getting a building with Get_Imm_Adv
+  will tell the client that another may be ahead in the tech race...
+*************************************************************************/
 static void update_improvement_from_packet(struct city *pcity,
                                           Impr_Type_id impr, bool have_impr,
                                           bool *impr_changed)
 {
   if (have_impr && pcity->improvements[impr] == I_NONE) {
-    city_add_improvement(pcity, impr);
+    city_add_improvement(pcity, impr, FALSE);
 
     if (impr_changed) {
       *impr_changed = TRUE;
@@ -319,7 +400,8 @@
 static void try_update_effects(bool need_update)
 {
   if (need_update) {
-    /* nothing yet... */
+    freelog(LOG_VERBOSE, "%%%%%%%%: try_update_effects"); /* DEBUGGING/REMOVE 
*/
+    effects_update_all();
   }
 }
 
@@ -469,6 +551,10 @@
     /* Initialise list of improvements with city/building wide equiv_range. */
     improvement_status_init(pcity->improvements,
                            ARRAY_SIZE(pcity->improvements));
+
+    /* Initialise city's vector of improvement effects. */
+    effect_vector_init(&pcity->effects);
+    effect_vector_init(&pcity->impr_effects);
   }
   copy_worklist(&pcity->worklist, &packet->worklist);
   pcity->did_buy=packet->did_buy;
@@ -500,15 +586,17 @@
     }
   }
   
+  effects_defer_update();
   impr_type_iterate(i) {
-    if (pcity->improvements[i] == I_NONE && packet->improvements[i] == '1'
-       && !city_is_new) {
+    if (pcity->improvements[i] == I_NONE && packet->improvements[i] == '1' 
+        && !city_is_new) {
       audio_play_sound(get_improvement_type(i)->soundtag,
                       get_improvement_type(i)->soundtag_alt);
     }
-    update_improvement_from_packet(pcity, i, packet->improvements[i] == '1',
+    update_improvement_from_packet(pcity, i, packet->improvements[i] == '1', 
                                    &need_effect_update);
   } impr_type_iterate_end;
+  effects_undefer_update();
 
   /* Since we can see inside the city, just determine the client status
    * from what we know. */
@@ -673,6 +761,10 @@
     /* Initialise list of improvements with city/building wide equiv_range. */
     improvement_status_init(pcity->improvements,
                            ARRAY_SIZE(pcity->improvements));
+
+    /* Initialise city's improvement effects. */
+    effect_vector_init(&pcity->effects);
+    effect_vector_init(&pcity->impr_effects);
   }
 
   update_improvement_from_packet(pcity, B_PALACE, packet->capital,
@@ -1392,13 +1484,20 @@
     pplayer->research.inventions[i].state = newstate;
     if (newstate != oldstate
        && (newstate == TECH_KNOWN || oldstate == TECH_KNOWN)) {
-      need_effect_update = TRUE;
+      /* if could be that we could lose tech at some point */
+      if (newstate == TECH_KNOWN) {
+        add_tech_effects(game.player_ptr, i, TRUE);
+        need_effect_update = TRUE;
+      } else if (oldstate == TECH_KNOWN) {
+        delete_effects(EFC_TECH, pplayer, NULL, NULL, i);
+        need_effect_update = TRUE;
+      }
     }
   } tech_type_iterate_end;
 
   if (need_effect_update) {
     improvements_update_obsolete();
-    /* need to update effects here too eventually */
+    effects_update_all();
   }
 
   update_research(pplayer);
@@ -1490,11 +1589,24 @@
   int i;
   bool poptechup, new_tech = FALSE;
   char msg[MAX_LEN_MSG];
+  int old_gov_id;
+  int old_nat_id;
+
   struct player *pplayer = &game.players[pinfo->playerno];
 
+  old_nat_id = pplayer->nation;
+  old_gov_id = pplayer->government;
+
   sz_strlcpy(pplayer->name, pinfo->name);
 
   pplayer->nation=pinfo->nation;
+
+  /* change nation effects if necessary */
+  if (old_nat_id != pplayer->nation) {
+    delete_effects(EFC_NATION, pplayer, NULL, NULL, old_nat_id);
+    add_nation_effects(pplayer, TRUE);
+  }
+
   pplayer->is_male=pinfo->is_male;
   pplayer->team = pinfo->team;
 
@@ -1503,6 +1615,13 @@
   pplayer->economic.science=pinfo->science;
   pplayer->economic.luxury=pinfo->luxury;
   pplayer->government=pinfo->government;
+
+  /* change government effects */
+  if (old_gov_id != pplayer->government) {
+    delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, old_gov_id);
+    add_government_effects(pplayer, TRUE);
+  }
+
   pplayer->embassy=pinfo->embassy;
   pplayer->gives_shared_vision = pinfo->gives_shared_vision;
   pplayer->city_style=pinfo->city_style;
@@ -1704,6 +1823,36 @@
   update_players_dialog();
 }
 
+/*************************************************************************
+ handle any global effects that we ought to know about.
+**************************************************************************/
+void handle_global_effect(bool add_effect, int player,
+                         struct effect_defn *effect_def)
+{
+  struct effect_defn *defn = fc_malloc(sizeof(struct effect_defn));
+  struct player *pplayer = get_player(player);
+
+  printf("in handle_global_effect(%s)\n",
+        add_effect ? "adding" : "deleting");
+  fflush(stdout);              /* DEBUGGING */
+
+  *defn = *effect_def;
+
+  if (add_effect) {
+    struct effect *eff = append_effect(pplayer, NULL, NULL, EFR_WORLD);
+    eff->defn = defn;
+    eff->plr = pplayer;
+    eff->home = NULL;
+    eff->id = -1;
+  } else {
+    delete_effect(pplayer, NULL, NULL, -1, defn);
+    /* FIXME: we need to free the defn in the game.effects vector */
+    free(defn);
+  }
+
+  effects_update_all();
+}
+
 /**************************************************************************
 Ideally the client should let the player choose which type of
 modules and components to build, and (possibly) where to extend
@@ -1970,6 +2119,7 @@
   if (ptile->continent > map.num_continents) {
     map.num_continents = ptile->continent;
     allot_island_improvs();
+    allot_island_effects();
   }
 
   /* refresh tiles */
@@ -2160,6 +2310,14 @@
 
   u->helptext = mystrdup(p->helptext);
 
+  effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+                             &u->effect_defs);
+ 
+#ifdef DEBUG
+  freelog(LOG_DEBUG, "%s", u->name);
+  print_effect_definitions(&u->effect_defs, "  effect...");
+#endif
+
   tilespec_setup_unit_type(p->id);
 }
 
@@ -2187,7 +2345,15 @@
   a->preset_cost = p->preset_cost;
   a->num_reqs = p->num_reqs;
   a->helptext = mystrdup(p->helptext);
-  
+
+  effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+                             &a->effect_defs);
+
+#ifdef DEBUG
+  freelog(LOG_DEBUG, "%s", a->name);
+  print_effect_definitions(&a->effect_defs, "  effect...");
+#endif
+
   tilespec_setup_tech_type(p->id);
 }
 
@@ -2236,11 +2402,8 @@
   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;
+  effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+                             &b->effect_defs);
 
 #ifdef DEBUG
   if(p->id == game.num_impr_types-1) {
@@ -2270,7 +2433,7 @@
                b->spec_gate[inx], get_special_name(b->spec_gate[inx]));
       }
       freelog(LOG_DEBUG, "  equiv_range %2d/%s",
-             b->equiv_range, effect_range_name(b->equiv_range));
+             b->equiv_range, impr_range_name(b->equiv_range));
       freelog(LOG_DEBUG, "  equiv_dupl...");
       for (inx = 0; b->equiv_dupl[inx] != B_LAST; inx++) {
        freelog(LOG_DEBUG, "    %2d/%s",
@@ -2291,78 +2454,9 @@
       freelog(LOG_DEBUG, "  build_cost %3d", b->build_cost);
       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_LAST) ?
-                   "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);
-      }
+
+      print_effect_definitions(&b->effect_defs, "  effect...");
+
       freelog(LOG_DEBUG, "  variant     %2d", b->variant);     /* FIXME: 
remove when gen-impr obsoletes */
       freelog(LOG_DEBUG, "  helptext    %s", b->helptext);
     } impr_type_iterate_end;
@@ -2451,6 +2545,14 @@
 
   gov->helptext = mystrdup(p->helptext);
   
+  effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+                             &gov->effect_defs);
+
+#ifdef DEBUG
+  freelog(LOG_DEBUG, "%s", gov->name);
+  print_effect_definitions(&gov->effect_defs, "  effect...");
+#endif
+
   tilespec_setup_government(p->id);
 }
 
@@ -2586,6 +2688,14 @@
   }
   pl->city_style = p->city_style;
 
+  effect_defn_array_to_vector(p->effect_defs, p->effect_defs_count,
+                             &pl->effect_defs);
+
+#ifdef DEBUG
+  freelog(LOG_DEBUG, "%s", pl->name);
+  print_effect_definitions(&pl->effect_defs, "  effect...");
+#endif
+
   if (p->class[0] != '\0') {
     pl->class = mystrdup(p->class);
   } else {
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand_gen.c 
snap-eff/client/packhand_gen.c
--- snap-pre/client/packhand_gen.c      2004-02-22 11:12:02.000000000 -0600
+++ snap-eff/client/packhand_gen.c      2004-03-05 20:55:17.000000000 -0600
@@ -298,6 +298,13 @@
     handle_ruleset_control(packet);
     return TRUE;
 
+  case PACKET_GLOBAL_EFFECT:
+    handle_global_effect(
+      ((struct packet_global_effect *)packet)->add_effect,
+      ((struct packet_global_effect *)packet)->player,
+      ((struct packet_global_effect *)packet)->effect_def);
+    return TRUE;
+
   default:
     return FALSE;
   }
diff -Nur -Xcvs/diff_ignore snap-pre/client/packhand_gen.h 
snap-eff/client/packhand_gen.h
--- snap-pre/client/packhand_gen.h      2004-02-22 11:12:02.000000000 -0600
+++ snap-eff/client/packhand_gen.h      2004-03-05 20:55:17.000000000 -0600
@@ -92,5 +92,6 @@
 void handle_ruleset_terrain(struct packet_ruleset_terrain *packet);
 struct packet_ruleset_control;
 void handle_ruleset_control(struct packet_ruleset_control *packet);
+void handle_global_effect(bool add_effect, int player, struct effect_defn 
*effect_def);
 
 #endif /* FC__PACKHAND_GEN_H */
diff -Nur -Xcvs/diff_ignore snap-pre/common/capstr.c snap-eff/common/capstr.c
--- snap-pre/common/capstr.c    2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/capstr.c    2004-03-05 20:45:56.000000000 -0600
@@ -76,7 +76,7 @@
 
 #define CAPABILITY "+1.14.delta +last_turns_shield_surplus veteran +orders " \
                    "+starter +union +iso_maps +orders2client " \
-                   "+change_production +tilespec1 +no_earth"
+                   "+change_production +tilespec1 +no_earth +effects"
 
 /* "+1.14.delta" is the new delta protocol for 1.14.0-dev.
  *
@@ -102,6 +102,8 @@
  *
  * "no_earth" means that the map.is_earth value is gone; replaced by
  * ptile->spec_sprite
+ *
+ * "effects" sends appropriate effect info to clients.
  */
 
 void init_our_capability(void)
diff -Nur -Xcvs/diff_ignore snap-pre/common/city.c snap-eff/common/city.c
--- snap-pre/common/city.c      2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/city.c      2004-03-05 20:46:34.000000000 -0600
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include "effects.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
@@ -466,10 +467,11 @@
 **************************************************************************/
 bool city_got_building(struct city *pcity,  Impr_Type_id id) 
 {
-  if (!improvement_exists(id))
+  if (!improvement_exists(id)) {
     return FALSE;
-  else 
+  } else { 
     return (pcity->improvements[id] != I_NONE);
+  }
 }
 
 /**************************************************************************
@@ -2426,7 +2428,8 @@
  arrays if the improvement has effects and/or an equiv_range that
  extend outside of the city.
 **************************************************************************/
-void city_add_improvement(struct city *pcity, Impr_Type_id impr)
+void city_add_improvement(struct city *pcity, Impr_Type_id impr, 
+                          bool add_immed_effects)
 {
   struct player *pplayer = city_owner(pcity);
 
@@ -2439,6 +2442,7 @@
   improvements_update_redundant(pplayer, pcity, 
                                 map_get_continent(pcity->x, pcity->y),
                                 improvement_types[impr].equiv_range);
+  add_improvement_effects(pcity, impr, add_immed_effects);
 }
 
 /**************************************************************************
@@ -2452,12 +2456,19 @@
   
   freelog(LOG_DEBUG,"Improvement %s removed from city %s",
           improvement_types[impr].name, pcity->name);
-  
+
   mark_improvement(pcity, impr, I_NONE);
 
+  /* some improvements may stop being redundant. */
   improvements_update_redundant(pplayer, pcity,
                                 map_get_continent(pcity->x, pcity->y),
                                 improvement_types[impr].equiv_range);
+
+  /* delete all of these improvement's effects */
+  delete_effects(EFC_IMPROVEMENT, NULL, pcity, NULL, impr);
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: removing improvement"); /* DEBUGGING/REMOVE 
*/
+  effects_update_all();
 }
 
 /**************************************************************************
@@ -2565,6 +2576,10 @@
   pcity->did_sell = FALSE;
   pcity->airlift = FALSE;
 
+  /* Initialise city's vector of improvement effects. */
+  effect_vector_init(&pcity->effects);
+  effect_vector_init(&pcity->impr_effects);
+
   pcity->turn_last_built = game.year;
   pcity->changed_from_id = 0;
   pcity->changed_from_is_unit = FALSE;
@@ -2605,6 +2620,10 @@
 **************************************************************************/
 void remove_city_virtual(struct city *pcity)
 {
+  /* free the effect structures */
+  effect_vector_free(&pcity->effects);
+  effect_vector_free(&pcity->impr_effects);
+
   unit_list_unlink_all(&pcity->units_supported);
   free(pcity);
 }
diff -Nur -Xcvs/diff_ignore snap-pre/common/city.h snap-eff/common/city.h
--- snap-pre/common/city.h      2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/city.h      2004-03-05 20:44:46.000000000 -0600
@@ -16,6 +16,7 @@
 #include "improvement.h"
 #include "unit.h"              /* struct unit_list */
 #include "worklist.h"
+#include "effects.h"
 
 struct player;
 struct government;
@@ -250,6 +251,8 @@
   int currently_building;
   
   Impr_Status improvements[B_LAST];
+  struct effect_vector effects;
+  struct effect_vector impr_effects; /* houses all local impr effects */
   
   struct worklist worklist;
 
@@ -456,7 +459,8 @@
 /* granary size as a function of city size */
 int city_granary_size(int city_size);
 
-void city_add_improvement(struct city *pcity,Impr_Type_id impr);
+void city_add_improvement(struct city *pcity,Impr_Type_id impr, 
+                          bool add_immed_effects);
 void city_remove_improvement(struct city *pcity,Impr_Type_id impr);
 
 /* city update functions */
@@ -490,7 +494,7 @@
  */
 #define built_impr_iterate(m_pcity, m_i)                                      \
   impr_type_iterate(m_i) {                                                    \
-    if((m_pcity)->improvements[m_i] == I_NONE) {                              \
+    if ((m_pcity)->improvements[m_i] == I_NONE) {                             \
       continue;                                                               \
     }
 
diff -Nur -Xcvs/diff_ignore snap-pre/common/dataio.c snap-eff/common/dataio.c
--- snap-pre/common/dataio.c    2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/dataio.c    2004-03-05 20:48:30.000000000 -0600
@@ -781,32 +781,39 @@
   dio_put_uint8(dout, pds->has_reason_to_cancel);
 }
 
-void dio_get_effect(struct data_in *din, struct impr_effect *peffect)
+void dio_get_effect_defn(struct data_in *din, struct effect_defn *defn)
 {
-  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));
+  dio_get_uint8(din, (int *) &defn->type);
+  dio_get_uint8(din, (int *) &defn->range);
+  dio_get_uint8(din, (int *) &defn->outside);
+  dio_get_sint16(din, (int *) &defn->amount);
+  dio_get_sint16(din, (int *) &defn->value1);
+  dio_get_sint16(din, (int *) &defn->value2);
+  dio_get_uint8(din, &defn->cond_bldg);
+  dio_get_uint32(din, &defn->cond_nat);
+  dio_get_uint8(din, &defn->cond_gov);
+  dio_get_uint8(din, &defn->cond_adv);
+  dio_get_uint8(din, (int *) &defn->cond_eff);
+  dio_get_uint8(din, (int *) &defn->aff_unit);
+  dio_get_uint8(din, (int *) &defn->aff_terr);
+  dio_get_uint16(din, (int *) &defn->aff_spec);
 }
 
-void dio_put_effect(struct data_out *dout, const struct impr_effect *peffect)
+void dio_put_effect_defn(struct data_out *dout,
+                         const struct effect_defn *defn)
 {
-  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);
+  dio_put_uint8(dout, defn->type);
+  dio_put_uint8(dout, defn->range);
+  dio_put_uint8(dout, defn->outside);
+  dio_put_sint16(dout, defn->amount);
+  dio_put_sint16(dout, defn->value1);
+  dio_put_sint16(dout, defn->value2);
+  dio_put_uint8(dout, defn->cond_bldg);
+  dio_put_uint32(dout, defn->cond_nat);
+  dio_put_uint8(dout, defn->cond_gov);
+  dio_put_uint8(dout, defn->cond_adv);
+  dio_put_uint8(dout, defn->cond_eff);
+  dio_put_uint8(dout, defn->aff_unit);
+  dio_put_uint8(dout, defn->aff_terr);
+  dio_put_uint16(dout, defn->aff_spec);
 }
diff -Nur -Xcvs/diff_ignore snap-pre/common/dataio.h snap-eff/common/dataio.h
--- snap-pre/common/dataio.h    2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/dataio.h    2004-03-05 20:44:46.000000000 -0600
@@ -17,7 +17,7 @@
 
 struct worklist;
 struct player_diplstate;
-struct impr_effect;
+struct effect_defn;
 
 struct data_in {
   const void *src;
@@ -71,7 +71,7 @@
 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_effect_defn(struct data_in *din, struct effect_defn *defn);
 
 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 +100,8 @@
 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_effect_defn(struct data_out *dout,
+                        const struct effect_defn * defn);
 
 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);
diff -Nur -Xcvs/diff_ignore snap-pre/common/effects.c snap-eff/common/effects.c
--- snap-pre/common/effects.c   2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/effects.c   2004-03-07 12:03:32.000000000 -0600
@@ -21,6 +21,7 @@
 #include "game.h"
 #include "government.h"
 #include "improvement.h"
+#include "log.h"
 #include "map.h"
 #include "mem.h"
 #include "support.h"
@@ -125,9 +126,82 @@
   "Upgrade_One_Leap",
   "Upgrade_All_Step",
   "Upgrade_All_Leap",
-  "Upkeep_Free"
+  "Upkeep_Free",
+  "Unit_Add_To_City",
+  "Unit_AEGIS",
+  "Unit_Airbase",
+  "Unit_Carrier",
+  "Unit_Cities",
+  "Unit_Diplomat",
+  "Unit_Fanatic",
+  "Unit_Field_Unit",
+  "Unit_Fighter",
+  "Unit_Game_Loss",
+  "Unit_Help_Wonder",
+  "Unit_Horse",
+  "Unit_Ignore_Terrain",
+  "Unit_Ignore_Tired",
+  "Unit_Ignore_Walls",
+  "Unit_Ignore_ZOC",
+  "Unit_Marines",
+  "Unit_Missile",
+  "Unit_Missile_Carrier",
+  "Unit_No_Home",
+  "Unit_No_Land_Attack",
+  "Unit_Nonmilitary",
+  "Unit_Nuclear",
+  "Unit_One_Attack",
+  "Unit_Paratroopers",
+  "Unit_Partial_Invisible",
+  "Unit_Pikemen",
+  "Unit_Settlers",
+  "Unit_Spy",
+  "Unit_Trade_Route",
+  "Unit_Transform",
+  "Unit_Trireme",
+  "Unit_Unbribable",
+  "Unit_Undisbandable",
+  "Unit_Super_Spy",
+  "Unit_Unique"
 };
 
+/* get 'struct effect_defn_vector' functions: */
+#define SPECVEC_TAG effect_defn
+#define SPECVEC_TYPE struct effect_defn
+#include "specvec_c.h"
+
+/* get 'struct effect_vector' functions: */
+#define SPECVEC_TAG effect
+#define SPECVEC_TYPE struct effect
+#include "specvec_c.h"
+
+/* does what it says if set */
+static bool defer_effects_update;
+
+/* effects update helpers */
+static void cache_effect(struct effect *eff);
+static bool effects_update_caches(void);
+static bool check_for_conditional_effect(struct effect *eff);
+
+/**************************************************************************
+ These effects are resolved immediately after being added to the effects
+ list and then removed.
+**************************************************************************/
+bool is_immediate_effect(struct effect_defn *defn)
+{
+  switch (defn->type) {
+  case EFT_GIVE_IMM_ADV:
+  case EFT_IMPROVE_REP:
+  case EFT_REVEAL_CITIES: /* this could be a continuing effect, anyone? */
+  case EFT_REVEAL_MAP:
+  case EFT_ENABLE_NUKE:   /* these two effects are only immediate in that */
+  case EFT_ENABLE_SPACE:  /* they flip bits which stay around */
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
 /**************************************************************************
   Convert effect range names to enum; case insensitive;
   returns EFR_LAST if can't match.
@@ -197,20 +271,971 @@
 /**************************************************************************
   Return TRUE iff the two effects are equal.
 **************************************************************************/
-bool are_effects_equal(const struct impr_effect *const peff1,
-                      const struct impr_effect *const peff2)
+bool are_effect_defns_equal(const struct effect_defn *const peff1,
+                           const struct effect_defn *const peff2)
 {
-#define T(name) if(peff1->name!=peff2->name) return FALSE;
+#define T(name) if(peff1->name != peff2->name) return FALSE;
   T(type);
   T(range);
+  T(outside);
   T(amount);
-  T(survives);
-  T(cond_bldg);
+  T(value1);
+  T(value2);
+
+  T(cond_nat);
   T(cond_gov);
   T(cond_adv);
+  T(cond_bldg);
   T(cond_eff);
+
   T(aff_unit);
   T(aff_terr);
   T(aff_spec);
   return TRUE;
+#undef T
+}
+
+/*******************************************************************
+  if pcity is NULL or the effect is active anyway, return active or pending. 
+  If pcity is non-NULL, check for the appropriate cond_bldg.
+********************************************************************/
+bool is_effect_emitting(struct effect *eff, struct city *pcity)
+{
+  if (!pcity || eff->has.active) {
+    return eff->has.active || eff->has.pending;
+  } else if (eff->has.pending) {
+    return city_got_building(pcity, eff->defn->cond_bldg);
+  } else {
+    return FALSE; /* effect not even pending a cond_bldg */
+  }
+}
+
+/******************************************************************
+ if pcity is non-NULL, global, player, and island ranges will return for 
+   their effect in that city and city and local ranges will be check in that
+   city only.
+ if id is not B_LAST, then all of the above applies and only id's effects in
+ the city are iterated through. If id is specified, pcity must also be.
+  
+*******************************************************************/
+void effect_iterator_init(struct effect_iter *iter, struct player *pplayer, 
+                          struct city *pcity, struct unit *punit,
+                          int id, enum effect_type type)
+{
+  assert(!(pcity && !pplayer)); /* can't have a city without a player */
+  assert((id != B_ALL && pcity) || id == B_ALL); /* need city with impr */
+
+  iter->type = type;
+  iter->player = pplayer;
+  iter->city = pcity;
+  iter->unit = punit;
+  iter->id = id;
+
+  iter->range = (punit) ? EFR_LOCAL : EFR_WORLD;
+ 
+  iter->end_range = EFR_WORLD;
+
+  if (pplayer) {
+    iter->end_range = EFR_PLAYER;
+  }
+  if (pcity) {
+    iter->end_range = EFR_CITY;
+  }
+  if (punit || id != B_ALL) {
+    iter->end_range = EFR_LOCAL;
+  }
+
+  iter->pos = 0;
+}
+
+/*******************************************************************
+ iterates through a particular range of effects returning the first one
+ that matches type and is active. If type is EFT_LAST, return all active
+ effects.
+
+ this function will pick up where it left off if you input the iter
+ used before. see the city_effects_iterate() macro in effects.h for usage.
+********************************************************************/
+struct effect *effect_iterator_get_next_active(struct effect_iter *iter)
+{
+  unsigned short cont;
+  struct effect *eff = NULL;
+
+#define CHECK_LIST(effect_vector, _pcity, _id)                              \
+  for ( ; iter->pos < effect_vector_size(&(effect_vector)); iter->pos++) {  \
+    eff = effect_vector_get(&(effect_vector), iter->pos);                   \
+                                                                            \
+    if ((eff->defn->type == iter->type || iter->type == EFT_ALL)            \
+        && is_effect_emitting(eff, (_pcity))                                \
+        && ((_id) == B_ALL || (_id) == eff->id)) {                          \
+      iter->pos++;                                                          \
+      return eff;                                                           \
+    }                                                                       \
+  }                                                                         \
+  iter->pos = 0;
+
+  while(iter->range >= iter->end_range) {
+    switch (iter->range) {
+    case EFR_WORLD:
+      CHECK_LIST(game.effects, iter->city, B_ALL);
+      break;         
+    case EFR_PLAYER:
+      CHECK_LIST(iter->player->effects, iter->city, B_ALL);
+      break;         
+    case EFR_ISLAND:
+      cont = map_get_continent(iter->city->x, iter->city->y);
+      CHECK_LIST(iter->player->island_effects[cont], iter->city, B_ALL);
+      break;
+    case EFR_CITY:
+      CHECK_LIST(iter->city->effects, NULL, B_ALL);     /* cond_bldg cached */
+      break;
+    case EFR_LOCAL:
+      if (iter->unit) {
+        /* nothing yet */
+      } else {
+        CHECK_LIST(iter->city->impr_effects, NULL, iter->id);
+      }
+      break;
+    default:
+      break;
+    }
+
+    if (iter->range == EFR_LOCAL) {
+      break;
+    } else {
+      iter->range--;
+    }
+  }
+
+  return NULL;
+
+#undef CHECK_LIST
+}
+
+/*******************************************************************
+ if set, effects_update_all will do nothing until until 
+ effects_undefer_update is called. these are used in savegame.c
+********************************************************************/
+void effects_defer_update(void)
+{
+  defer_effects_update = TRUE;
+}
+
+/*******************************************************************
+  allows effects_update_all to function.
+********************************************************************/
+void effects_undefer_update(void)
+{
+  defer_effects_update = FALSE;
+}
+
+/*******************************************************************
+ iterate through all effects --- perhaps multiple times --- to activate
+ all effects. be all that you can be.
++
+ TODO: possibly there's an optimization to be make inside the cond_eff loop.
+       if there are no effects in game.effects with !eff->has_eff, then we 
+       only need to loop within a player anytime there is a change rather 
+       than over all players every time.
+********************************************************************/
+void effects_update_all_common(void)
+{
+  int i;
+  bool changed = TRUE;
+  bool needs_condeff;
+
+  if (defer_effects_update) {
+    return;
+  }
+
+  freelog(LOG_DEBUG, "updating all effects");
+
+  needs_condeff = effects_update_caches();
+
+  /* check for cond_eff and activate effects as necessary
+   * you don't want to even contemplate the worst-case scenario here ;) */
+  while(needs_condeff && changed) {
+    freelog(LOG_DEBUG, "effects_update_all: needed to loop for cond_eff");
+    changed = FALSE;
+
+    /* global effects */
+    effect_vector_iterate(game.effects, eff) {
+      changed = check_for_conditional_effect(eff);
+    } effect_vector_iterate_end;
+   
+    players_iterate(pplayer) {
+      /* player effects */
+      effect_vector_iterate(pplayer->effects, eff) {
+        changed = check_for_conditional_effect(eff);
+      } effect_vector_iterate_end;
+  
+      /* island effects */   
+      for(i = 1; i <= map.num_continents; i++) {
+        effect_vector_iterate(pplayer->island_effects[i], eff) {
+          changed = check_for_conditional_effect(eff);
+        } effect_vector_iterate_end;
+      }
+
+      /* city effects */   
+      city_list_iterate(pplayer->cities, pcity) {
+        effect_vector_iterate(pcity->effects, eff) {
+          changed = check_for_conditional_effect(eff);
+        } effect_vector_iterate_end;
+
+        /* local effects */    
+        effect_vector_iterate(pcity->impr_effects, eff) {
+          changed = check_for_conditional_effect(eff);
+        } effect_vector_iterate_end;
+      } city_list_iterate_end;
+    } players_iterate_end;
+  }
+} 
+
+/*******************************************************************
+ caches as many of the requirements of an effect as we possibly can
+ since if we have to loop for cond_eff, we don't want to recalculate
+ these each time.
+********************************************************************/
+static void cache_effect(struct effect *eff)
+{
+  /* store this for later comparison */
+  eff->has.changed = 0;
+  eff->has.was_active = (eff->has.active || eff->has.pending);
+
+  eff->has.nat = (eff->defn->cond_nat == -1
+                  || eff->defn->cond_nat == eff->plr->nation);
+
+#undef BIGDEBUG /* FIXME: delete all BIGDEBUGs before commit. */
+#define BIGDEBUG /* FIXME: delete all BIGDEBUGs before commit. */
+
+#ifdef BIGDEBUG
+  if (!eff->has.nat) {
+    freelog(LOG_DEBUG, 
+            "cache_effect: (no req. nat) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+#endif
+  eff->has.adv = (eff->defn->cond_adv == A_NONE
+                  || get_invention(eff->plr, 
+                                   eff->defn->cond_adv) == TECH_KNOWN);
+#ifdef BIGDEBUG
+  if (!eff->has.adv) { 
+    freelog(LOG_DEBUG, 
+            "cache_effect: (no req. adv) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+#endif
+  eff->has.gov = (eff->defn->cond_gov == game.government_count
+                  || eff->defn->cond_gov == eff->plr->government);
+
+  if (!eff->has.gov) {
+    freelog(LOG_DEBUG, 
+            "cache_effect: (no req. gov) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+
+  /* this depends on the city we're looking at, can't fully cache
+   * except if the effect's range is city or less. */
+  /* the || should protect eff->home from being evaluated if NULL ??? */
+  eff->has.bldg = (eff->defn->cond_bldg == B_LAST 
+                   || (eff->defn->range < EFR_ISLAND
+                       && city_got_building(eff->home, eff->defn->cond_bldg)));
+
+#ifdef BIGDEBUG
+  if (!eff->has.bldg) {
+    freelog(LOG_DEBUG,
+            "cache_effect: (no bldg) p: %s c: %s i: %d r: %s n: %s"
+            "\n\t\t\t bldg: %s s:%d e:%d",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type), 
+            get_improvement_name(eff->defn->cond_bldg), 
+            eff->home->improvements[eff->defn->cond_bldg], 
+            improvement_exists(eff->defn->cond_bldg));
+  }
+#endif
+
+  /* redundant buildings have their effects suppressed */
+  if (eff->home) {
+    eff->has.no_equiv = (eff->home->improvements[eff->id] != I_REDUNDANT);
+  } else {
+    eff->has.no_equiv = TRUE;
+  }
+
+#ifdef BIGDEBUG
+  if (!eff->has.no_equiv) {
+    freelog(LOG_DEBUG, 
+            "cache_effect: (sup. by equiv) p: %s c: %s i: %d r: %s n: %s", 
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+#endif
+
+  /* requires multiple passes, can't fully cache */
+  eff->has.condeff = (eff->defn->cond_eff == EFT_LAST);
+
+#ifdef BIGDEBUG
+  if (!eff->has.condeff) {
+    freelog(LOG_DEBUG, 
+            "cache_effect: (no req. cond_eff) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+#endif
+
+  eff->has.pending = eff->has.nat && eff->has.gov && eff->has.adv 
+                     && eff->has.no_equiv && eff->has.condeff;
+  eff->has.active = eff->has.pending && eff->has.bldg;
+
+#ifdef BIGDEBUG
+  if (eff->has.pending && !eff->has.active) {
+    freelog(LOG_DEBUG,
+            "cache_effect: (pending) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+
+  if (eff->has.active) {
+    freelog(LOG_DEBUG,
+            "cache_effect: (active) p: %s c: %s i: %d r: %s n: %s",
+            eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+  }
+#endif
+
+  eff->has.changed = eff->has.was_active ^ 
+                     (eff->has.active || eff->has.pending);
+}
+
+/*******************************************************************
+ cache each effect for everything except for conditional effects and 
+ buildings.
+
+ return TRUE if any of the effects have a cond_eff.
+********************************************************************/
+static bool effects_update_caches(void)
+{
+  int i;
+  bool condeff_flag = FALSE;
+ 
+  /* global effects */
+  effect_vector_iterate(game.effects, eff) {
+    cache_effect(eff);
+    condeff_flag |= !eff->has.condeff;
+  } effect_vector_iterate_end;
+
+  players_iterate(pplayer) {
+    /* player effects */
+    effect_vector_iterate(pplayer->effects, eff) {
+      cache_effect(eff);
+      condeff_flag |= !eff->has.condeff;
+    } effect_vector_iterate_end;
+
+    /* island effects */
+    for(i = 1; i <= map.num_continents; i++) {
+      effect_vector_iterate(pplayer->island_effects[i], eff) {
+        cache_effect(eff);
+        condeff_flag |= !eff->has.condeff;
+      } effect_vector_iterate_end;
+    }
+
+    /* city effects */
+    city_list_iterate(pplayer->cities, pcity) {
+      effect_vector_iterate(pcity->effects, eff) {
+        cache_effect(eff);
+        condeff_flag |= !eff->has.condeff;
+      } effect_vector_iterate_end;
+
+      /* local impr effects */
+      effect_vector_iterate(pcity->impr_effects, eff) {
+        cache_effect(eff);
+        condeff_flag |= !eff->has.condeff;
+      } effect_vector_iterate_end;
+    } city_list_iterate_end;
+  } players_iterate_end;
+
+  return condeff_flag;
+}
+
+/*******************************************************************
+ does a complete check for prerequisite effects for eff
+ if we find an active effect that satisfies cond_eff, then we activate the
+ eff or set its pending status and then return TRUE (so we stop after the
+ first positive result)
+
+ remember that the origin of the effect (the improvement generating it)
+ must be within the range of the cond_eff.
+
+ N.B. Depending on the cond_eff dependencies of future popular mod-packs, 
+ these checks might be rearranged to get a faster hit.
+********************************************************************/
+static bool check_for_conditional_effect(struct effect *eff)
+{
+  int cont;
+
+#define CHECK_CONDEFF(eff, eff2)                                           \
+   if ((eff)->defn->cond_eff == (eff2)->defn->type                         \
+       && is_effect_emitting((eff2), (eff)->home)) {                       \
+     if (eff->has.bldg) {                                                  \
+       (eff)->has.active = TRUE;                                           \
+     } else {                                                              \
+       (eff)->has.pending = TRUE;                                          \
+     }                                                                     \
+                                                                           \
+     eff->has.changed = eff->has.was_active ^                              \
+                        (eff->has.active || eff->has.pending);             \
+                                                                           \
+     freelog(LOG_DEBUG, "effects: (cond eff found) "                       \
+             "p: %s c: %s i: %d r: %s n: %s",                              \
+             eff->plr->name, (eff->home) ? eff->home->name : "(homeless)", \
+             eff->id, effect_range_name(eff->defn->range),                 \
+             effect_type_name(eff->defn->type));                           \
+                                                                           \
+     return TRUE;                                                          \
+   }
+
+  /* FIXME: this is buggy I think, or at the least needs optimization */
+  /* if there is no cond_eff and all other prereqs are there, continue */
+  if (eff->has.pending || !eff->home 
+      || !(eff->has.nat && eff->has.gov && eff->has.adv)) {
+    return FALSE;
+  }
+
+  /* does any global cond_eff affect eff's origin? */
+  effect_vector_iterate(game.effects, eff2) {
+    CHECK_CONDEFF(eff, eff2);
+  } effect_vector_iterate_end;
+
+  /* does any player-wide cond_eff affect eff's origin? */
+  effect_vector_iterate(eff->plr->effects, eff2) {
+    CHECK_CONDEFF(eff, eff2);
+  } effect_vector_iterate_end;
+
+  /* homeless? */
+  if (!eff->home) {
+    return FALSE;
+  }
+
+  /* does any island-wide cond_eff affect eff's origin? */
+  cont = map_get_continent(eff->home->x, eff->home->y);
+
+  effect_vector_iterate(eff->plr->island_effects[cont], eff2) {
+    CHECK_CONDEFF(eff, eff2);
+  } effect_vector_iterate_end;
+
+  /* does any city-wide cond_eff affect eff's origin? */
+  effect_vector_iterate(eff->home->effects, eff2) {
+    CHECK_CONDEFF(eff, eff2);
+  } effect_vector_iterate_end;
+
+  /* does any local cond_eff affect eff's origin? */
+  effect_vector_iterate(eff->home->impr_effects, eff2) {
+    if (eff->id == eff2->id) {
+      CHECK_CONDEFF(eff, eff2);
+    }
+  } effect_vector_iterate_end;
+
+  /* no hits */
+  return FALSE;
+
+#undef CHECK_CONDEFF
+}
+
+/*******************************************************************
+ return a struct effect from the end of the proper vector, extending
+ the vector if necessary
+********************************************************************/
+struct effect *append_effect(struct player *pplayer, struct city *home, 
+                             struct unit *punit, enum effect_range range)
+{
+  int n, cont;
+
+#define RETURN_NEW_EFFECT(_vec)                                             \
+  n = effect_vector_size(&(_vec));                                          \
+  effect_vector_reserve(&(_vec), n + 1);                                    \
+  return effect_vector_get(&(_vec), n);
+
+  /* range is always EFR_LOCAL */
+  if (punit) {
+    RETURN_NEW_EFFECT(punit->effects);
+  }
+
+  switch(range) {
+  case EFR_WORLD:
+    RETURN_NEW_EFFECT(game.effects);
+  case EFR_PLAYER:
+    RETURN_NEW_EFFECT(pplayer->effects);
+  case EFR_ISLAND:
+    cont = map_get_continent(home->x, home->y);
+    RETURN_NEW_EFFECT(pplayer->island_effects[cont]);
+  case EFR_CITY:
+    RETURN_NEW_EFFECT(home->effects);
+  case EFR_LOCAL:
+    RETURN_NEW_EFFECT(home->impr_effects);
+  default:
+    assert(0);
+    return NULL;
+  } 
+
+#undef RETURN_NEW_EFFECT
+}
+
+/*******************************************************************
+ add effect_vector from a nation
+********************************************************************/
+void add_nation_effects(struct player *pplayer,  bool add_immed_effects)
+{
+  bool need_update = FALSE;
+
+  effect_defn_vector_iterate(get_nation_by_plr(pplayer)->effect_defs, defn) {
+    struct effect *eff;
+
+    if (!add_immed_effects && is_immediate_effect(defn)) {
+      continue;
+    }
+
+    eff = append_effect(pplayer, NULL, NULL, defn->range);   
+
+    eff->plr = pplayer;
+    eff->home = NULL;
+    eff->unit = NULL;
+    eff->id = pplayer->nation;
+    eff->defn = defn;
+    eff->has.active = eff->has.pending = 0;
+
+    freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s", 
+            eff->plr->name, "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+
+    need_update = TRUE;
+  } effect_defn_vector_iterate_end;
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: add nation effects"); /* DEBUGGING/REMOVE */
+  if (need_update) {
+    effects_update_all();
+  }
+}
+
+/*******************************************************************
+ add effect_vector from an tech
+********************************************************************/
+void add_tech_effects(struct player *pplayer, int id,  bool add_immed_effects)
+{
+  bool need_update = FALSE;
+
+  /* kludge: A_FUTURE can't yet have effects! :( */
+  if (id == A_FUTURE) {
+    return;
+  }
+
+  effect_defn_vector_iterate(advances[id].effect_defs, defn) { 
+    struct effect *eff;
+
+    if (!add_immed_effects && is_immediate_effect(defn)) {
+      continue;
+    }
+
+    eff = append_effect(pplayer, NULL, NULL, defn->range);
+
+    eff->plr = pplayer;
+    eff->home = NULL;
+    eff->unit = NULL;
+    eff->id = id;
+    eff->defn = defn;
+    eff->has.active = eff->has.pending = 0;
+
+    freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s", 
+            eff->plr->name, "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+
+    need_update = TRUE;
+  } effect_defn_vector_iterate_end;
+
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: add tech effects"); /* DEBUGGING/REMOVE */
+  if (need_update) {
+    effects_update_all();
+  }
+}
+
+/*******************************************************************
+ add effect_vector from a government
+********************************************************************/
+void add_government_effects(struct player *pplayer,  bool add_immed_effects)
+{
+  bool need_update = FALSE;
+
+  effect_defn_vector_iterate(governments[pplayer->government].effect_defs, 
+                             defn) {         
+    struct effect *eff;
+
+    if (!add_immed_effects && is_immediate_effect(defn)) {
+      continue;
+    }
+
+    eff = append_effect(pplayer, NULL, NULL, defn->range);
+
+    eff->plr = pplayer;
+    eff->home = NULL;
+    eff->unit = NULL;
+    eff->id = pplayer->government;
+    eff->defn = defn;
+    eff->has.active = eff->has.pending = 0;
+
+    freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s", 
+            eff->plr->name, "(homeless)", 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+
+    need_update = TRUE;
+  } effect_defn_vector_iterate_end;
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: add gov effects"); /* DEBUGGING/REMOVE */
+  if (need_update) {
+    effects_update_all();
+  }
+}
+
+/*******************************************************************
+ add effect_vector from an improvement
+********************************************************************/
+void add_improvement_effects(struct city *pcity, int id, bool 
add_immed_effects)
+{
+  bool need_update = FALSE;
+
+  effect_defn_vector_iterate(improvement_types[id].effect_defs, defn) { 
+    struct effect *eff;
+    struct player *pplayer = city_owner(pcity);
+
+    if (!add_immed_effects && is_immediate_effect(defn)) {
+      continue;
+    }
+
+    eff = append_effect(pplayer, pcity, NULL, defn->range);
+
+    eff->plr = pplayer;
+    eff->home = pcity;
+    eff->unit = NULL;
+    eff->id = id;
+    eff->defn = defn;
+    eff->has.active = eff->has.pending = 0;
+
+    freelog(LOG_DEBUG, "added effect p: %s c: %s i: %d r: %s n: %s", 
+            eff->plr->name, eff->home->name, 
+            eff->id, effect_range_name(eff->defn->range), 
+            effect_type_name(eff->defn->type));
+
+    need_update = TRUE;
+
+  } effect_defn_vector_iterate_end;
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: add improvement effects"); /* 
DEBUGGING/REMOVE */
+  if (need_update) {
+    effects_update_all();
+  }
+}
+
+/*******************************************************************
+ add effect_vector for a unit
+********************************************************************/
+void add_unit_effects(struct unit *punit, bool add_immed_effects)
+{
+  bool need_update = FALSE;
+  Unit_Type_id type = punit->type;
+
+  effect_defn_vector_iterate(unit_types[type].effect_defs, defn) {
+    struct effect *eff;
+    struct player *pplayer = unit_owner(punit);
+
+    if (!add_immed_effects && is_immediate_effect(defn)) {
+      continue;
+    }
+
+    eff = append_effect(pplayer, NULL, punit, defn->range);
+
+    eff->plr = pplayer;
+    eff->home = NULL;
+    eff->unit = punit;
+    eff->id = type;
+    eff->defn = defn;
+    eff->has.active = eff->has.pending = 0;
+
+    freelog(LOG_DEBUG, "added effect p: %s u: %s i: %d r: %s n: %s",
+            eff->plr->name, unit_name(type), 
+            eff->id, effect_range_name(eff->defn->range),
+            effect_type_name(eff->defn->type));
+
+    need_update = TRUE;
+
+  } effect_defn_vector_iterate_end;
+
+  freelog(LOG_VERBOSE, "%%%%%%%%: add unit effects"); /* DEBUGGING/REMOVE */
+
+  if (need_update) {
+    effects_update_all();
+  }
+}
+
+/*******************************************************************
+ called when the number of continents changes 
+
+ for each player, we place all the Island-ranged effects from each
+ continent into a holding vector, resize pplayer->island_effects
+ and then reinsert the effects from the holding vector back into
+ the appropriate island_effects vector.
+********************************************************************/
+void allot_island_effects(void)
+{
+  int i, s, size = 0;
+  static unsigned short old_num_cont;
+  struct effect_vector holding;
+
+  freelog(LOG_DEBUG, "reallotting island effects old:%d cur:%d",
+          old_num_cont, map.num_continents);
+
+#define ADD_EFFECT(_vec, _eff)                                             \
+  effect_vector_reserve(&(_vec), effect_vector_size(&(_vec)) + 1);         \
+  memcpy(effect_vector_get(&(_vec), effect_vector_size(&(_vec)) - 1),      \
+         (_eff), sizeof(struct effect));
+
+  players_iterate(pplayer) {
+    /* create a holding place for the effects */
+    effect_vector_init(&holding);
+  
+    /* store all the island effects in a holding list */
+    for (i = 1; i <= old_num_cont; i++) {
+      size += effect_vector_size(&pplayer->island_effects[i]);
+    }
+    effect_vector_reserve(&holding, size);
+  
+    for (s = 0, i = 1; i <= old_num_cont; i++) {
+      effect_vector_iterate(pplayer->island_effects[i], eff) {
+        memcpy(effect_vector_get(&holding, s++), eff, sizeof(struct effect));
+      } effect_vector_iterate_end;
+  
+      effect_vector_free(&pplayer->island_effects[i]);
+    }
+  
+    /* reallocate and init island lists */
+    pplayer->island_effects = fc_realloc(pplayer->island_effects,
+                                         (map.num_continents + 1)
+                                         * sizeof(struct effect_vector));
+  
+    for (i = 1; i <= map.num_continents; i++) {
+      effect_vector_init(&pplayer->island_effects[i]);
+    }
+  
+    /* reinsert */
+    effect_vector_iterate(holding, eff) {
+      int cont = map_get_continent(eff->home->x, eff->home->y);
+  
+      ADD_EFFECT(pplayer->island_effects[cont], eff); 
+    } effect_vector_iterate_end;
+  
+  
+    effect_vector_free(&holding);
+  } players_iterate_end;
+
+#undef ADD_EFFECT
+
+  /* save for next time around */
+  old_num_cont = map.num_continents;
+
+  effects_update_all();
+}
+
+/*******************************************************************
+ delete all effects specified by the nation's effect_defs
+********************************************************************/
+static void delete_nation_effects(struct player *pplayer, int id)
+{
+  /* player.c sets the default nation to this value. don't cause a core */
+  if (id == NO_NATION_SELECTED) {
+    return;
+  }
+
+  effect_defn_vector_iterate(get_nation_by_idx(id)->effect_defs, defn) {
+    delete_effect(pplayer, NULL, NULL, id, defn);
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the tech's effect_defs
+********************************************************************/
+static void delete_tech_effects(struct player *pplayer, int id)
+{
+  /* kludge: A_FUTURE can't yet have effects! :( */
+  if (id == A_FUTURE) {
+    return;
+  }
+
+  effect_defn_vector_iterate(advances[id].effect_defs, defn) {
+    delete_effect(pplayer, NULL, NULL, id, defn);
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the governments's effect_defs
+********************************************************************/
+static void delete_government_effects(struct player *pplayer, int id)
+{
+  /* game.c sets the default government to this value. */
+  if (id == G_MAGIC) {
+    return;
+  }
+
+  effect_defn_vector_iterate(governments[id].effect_defs, defn) {
+    delete_effect(pplayer, NULL, NULL, id, defn);
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the improvment's effect_defs
+********************************************************************/
+static void delete_improvement_effects(struct city *pcity, int id)
+{
+  effect_defn_vector_iterate(improvement_types[id].effect_defs, defn) {
+    delete_effect(city_owner(pcity), pcity, NULL, id, defn);
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects specified by the unit's effect_defs
+********************************************************************/
+static void delete_unit_effects(struct unit *punit)
+{
+  effect_defn_vector_iterate(unit_type(punit)->effect_defs, defn) {
+    delete_effect(unit_owner(punit), NULL, punit, -1, defn);
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ delete all effects for a particular effect_defn_vector
+********************************************************************/
+void delete_effects_common(enum effect_class class, struct player *pplayer, 
+                           struct city *pcity, struct unit *punit, int id)
+{
+  switch (class) {
+  case EFC_UNIT:
+    delete_unit_effects(punit);
+    break;
+  case EFC_IMPROVEMENT:
+    delete_improvement_effects(pcity, id);
+    break;
+  case EFC_TECH:
+    delete_tech_effects(pplayer, id);
+    break;
+  case EFC_GOVERNMENT:
+    delete_government_effects(pplayer, id);
+    break;
+  case EFC_NATION:
+    delete_nation_effects(pplayer, id);
+    break;
+  default:
+    assert(0);
+  }
+}
+
+/*******************************************************************
+ remove an effect (via its definition) from its vector.
+ this will delete all such effects that match the parameters given.
+
+ you need to update all effects manually after this.
+********************************************************************/
+void delete_effect(struct player *pplayer, struct city *pcity, 
+                   struct unit *punit, int id, struct effect_defn *defn)
+{
+
+#define SEARCH_LIST_AND_DEL(eff_list)                                        \
+{                                                                            \
+  int i = 0, size = effect_vector_size(&(eff_list));                         \
+  while (i < size) {                                                         \
+    struct effect *_eff = effect_vector_get(&(eff_list), i);                 \
+    if (are_effect_defns_equal(_eff->defn, defn)                             \
+        && (!pplayer || _eff->plr == pplayer)                                \
+        && (!pcity || _eff->home == pcity)                                   \
+        && (id == B_LAST || _eff->id == id)) {                               \
+      freelog(LOG_DEBUG, "deleted effect p: %s, c: %s i: %d n: %s",          \
+              pplayer->name, (pcity) ? pcity->name : "(homeless)",           \
+              id, effect_type_name(defn->type));                             \
+      memcpy(_eff, effect_vector_get(&(eff_list), size - 1),                 \
+             sizeof(struct effect));                                         \
+      size--;                                                                \
+      (eff_list).vector.n--;                                                 \
+    } else {                                                                 \
+      i++;                                                                   \
+    }                                                                        \
+  }                                                                          \
+}
+
+  switch(defn->range) {
+  case EFR_WORLD:
+    SEARCH_LIST_AND_DEL(game.effects);
+    break;
+  case EFR_PLAYER:
+    assert(pplayer);
+    SEARCH_LIST_AND_DEL(pplayer->effects);
+    break;
+  case EFR_ISLAND:
+    assert(pplayer);
+    SEARCH_LIST_AND_DEL(pplayer->island_effects[id]);
+    break;
+  case EFR_CITY:
+    assert(pcity);
+    SEARCH_LIST_AND_DEL(pcity->effects);
+    break;
+  case EFR_LOCAL:
+    assert(pcity || punit);
+    if (pcity) {
+      SEARCH_LIST_AND_DEL(pcity->impr_effects);
+    } else {
+      SEARCH_LIST_AND_DEL(punit->effects);
+    }    
+    break;
+  default:
+    break;
+  }
+
+#undef SEARCH_LIST_AND_DEL
+}
+
+/*******************************************************************
+ copy the vectors of an effect_defn_vector into an array for packetization.
+********************************************************************/
+void effect_defn_vector_to_array(const struct effect_defn_vector *vector,
+                                struct effect_defn *array, int *array_count)
+{
+  *array_count = 0;
+  effect_defn_vector_iterate(*vector, item) {
+    array[*array_count] = *item;
+    (*array_count)++;
+  } effect_defn_vector_iterate_end;
+}
+
+/*******************************************************************
+ copy an array of vectors of effect_defn into a effect_defn_vector.
+********************************************************************/
+void effect_defn_array_to_vector(const struct effect_defn *array,
+                                int array_count,
+                                struct effect_defn_vector *vector)
+{
+  int i;
+
+  effect_defn_vector_init(vector);
+  effect_defn_vector_reserve(vector, array_count);
+  for (i = 0; i < array_count; i++) {
+    *effect_defn_vector_get(vector, i) = array[i];
+  }
 }
diff -Nur -Xcvs/diff_ignore snap-pre/common/effects.h snap-eff/common/effects.h
--- snap-pre/common/effects.h   2003-12-14 18:20:46.000000000 -0600
+++ snap-eff/common/effects.h   2004-03-05 20:44:46.000000000 -0600
@@ -18,6 +18,19 @@
 #include "shared.h"            /* bool */
 #include "terrain.h"
 
+struct player;
+struct city;
+
+/* the different classes an effect could belong to. 
+ * certain classes can only have certain ranges */
+enum effect_class {
+  EFC_UNIT,
+  EFC_IMPROVEMENT,
+  EFC_TECH,
+  EFC_GOVERNMENT,
+  EFC_NATION
+};
+
 /* Range of effects (used in equiv_range and effect.range fields)
  * These must correspond to effect_range_names[] in improvement.c. */
 enum effect_range {
@@ -116,18 +129,243 @@
   EFT_UPGRADE_ALL_STEP,
   EFT_UPGRADE_ALL_LEAP,
   EFT_UPKEEP_FREE,
-  EFT_LAST     /* keep this last */
+  EFT_UNIT_ADD_TO_CITY,
+  EFT_UNIT_AEGIS,
+  EFT_UNIT_AIRBASE,
+  EFT_UNIT_CARRIER,
+  EFT_UNIT_CITIES,
+  EFT_UNIT_DIPLOMAT,
+  EFT_UNIT_FANATIC,
+  EFT_UNIT_FIELD_UNIT,
+  EFT_UNIT_FIGHTER,
+  EFT_UNIT_GAME_LOSS,
+  EFT_UNIT_HELP_WONDER,
+  EFT_UNIT_HORSE,
+  EFT_UNIT_IGNORE_TERRAIN,
+  EFT_UNIT_IGNORE_TIRED,
+  EFT_UNIT_IGNORE_WALLS,
+  EFT_UNIT_IGNORE_ZOC,
+  EFT_UNIT_MARINES,
+  EFT_UNIT_MISSILE,
+  EFT_UNIT_MISSILE_CARRIER,
+  EFT_UNIT_NO_HOME,
+  EFT_UNIT_NO_LAND_ATTACK,
+  EFT_UNIT_NONMILITARY,
+  EFT_UNIT_NUCLEAR,
+  EFT_UNIT_ONE_ATTACK,
+  EFT_UNIT_PARATROOPERS,
+  EFT_UNIT_PARTIAL_INVISIBLE,
+  EFT_UNIT_PIKEMEN,
+  EFT_UNIT_SETTLERS,
+  EFT_UNIT_SPY,
+  EFT_UNIT_TRADE_ROUTE,
+  EFT_UNIT_TRANSFORM,
+  EFT_UNIT_TRIREME,
+  EFT_UNIT_UNBRIBABLE,
+  EFT_UNIT_UNDISBANDABLE,
+  EFT_UNIT_SUPER_SPY,
+  EFT_UNIT_UNIQUE,
+
+  EFT_LAST                     /* keep this last */
 };
 
 #define EFT_ALL EFT_LAST
 
+/* an effect definition. lists of these are in: 
+ * nation, government, tech, improvement, and soon-to-be-in unit structs */
+struct effect_defn {
+  enum effect_type type;
+  enum effect_range range;
+  bool outside;                     /* affects outside of cities or center 
tile */ 
+  short amount;
+  short value1;              /* auxillary amount (paratroopers) */
+  short value2;              /* ditto */
+
+  int cond_nat;              /* actually Nation_Type_id */
+  int cond_gov;
+  int cond_adv;              /* actually Tech_Type_id */
+  int cond_bldg;             /* actually Impr_Type_id */
+  enum effect_type cond_eff; 
+
+  enum tile_terrain_type aff_terr; 
+  enum tile_special_type aff_spec; 
+  int aff_unit;              /* actually Unit_Class_id */
+};
+
+#define SPECVEC_TAG effect_defn
+#define SPECVEC_TYPE struct effect_defn
+#include "specvec.h"
+
+#define effect_defn_vector_iterate(_vec, _defn)                             \
+{                                                                           \
+  int _iter;                                                                \
+  struct effect_defn *_defn;                                                \
+  for (_iter = 0; _iter < effect_defn_vector_size(&(_vec)); _iter++) {      \
+    _defn = effect_defn_vector_get(&(_vec), _iter);
+
+#define effect_defn_vector_iterate_end                                      \
+  }                                                                         \
+}
+
+/* active, pending and has.* cache whether the effect is active */
+struct effect {
+  /* save a bunch of memory */
+  struct {
+    unsigned int active:1;      /* is effect active? */
+    unsigned int pending:1;     /* is effect active except for cond_bldg? */
+    unsigned int changed:1;     /* has effect changed since last update? */
+    unsigned int was_active:1;  /* temp variable for calculation of 'changed' 
*/
+
+    unsigned int nat:1;         /* has req. nation (or doesn't need one) */
+    unsigned int adv:1;         /* has req. advance (or doesn't need one) */
+    unsigned int gov:1;         /* has req. gov (or doesn't need one) */
+    unsigned int bldg:1;        /* has req. bldg (only partially cached) */
+    unsigned int condeff:1;     /* has cond_eff (only partially cached) */
+    unsigned int no_equiv:1;    /* there's no equivalent bldg that suppresses 
*/
+  } has;
+
+  struct player *plr;
+  struct city *home;       /* NULL if effect has no location (origin) */
+  struct unit *unit;       /* NULL if effect is not attached to a unit */
+  int id;                  /* id of thing generating effect */
+
+  struct effect_defn *defn;  /* a pointer to the effect definition */
+};
+
+#define SPECVEC_TAG effect 
+#define SPECVEC_TYPE struct effect
+#include "specvec.h"
+
+#define effect_vector_iterate(_vec, _eff)                                   \
+{                                                                           \
+  int _iter;                                                                \
+  struct effect *_eff;                                                      \
+  for (_iter = 0; _iter < effect_vector_size(&(_vec)); _iter++) {           \
+    _eff = effect_vector_get(&(_vec), _iter);
+
+#define effect_vector_iterate_end                                           \
+  }                                                                         \
+}
+
+struct effect_iter {
+  /* these are set by the user */
+  enum effect_type type; /* what type to look for. EFT_ALL returns all */
+  struct player *player; /* if NULL, only EFR_WORLD */
+  struct city *city;     /* if !NULL, all effects affecting this city */
+  struct unit *unit;     /* if !NULL, all effects affecting this unit */
+  int id;                /* if !B_ALL, all effects affecting this impr */
+
+  /* these are internal. They track and end the iteration */
+  enum effect_range range;
+  enum effect_range end_range;
+  int pos;
+};
+
 /* lookups */
+bool is_immediate_effect(struct effect_defn *defn);
 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_effect_defns_equal(const struct effect_defn *const peff1,
+                           const struct effect_defn *const peff2);
+
+/* retrieval */
+bool is_effect_emitting(struct effect *eff, struct city *pcity);
+void effect_iterator_init(struct effect_iter *iter, struct player *pplayer, 
+                          struct city *pcity, struct unit *punit,
+                          int id, enum effect_type type);
+struct effect *effect_iterator_get_next_active(struct effect_iter *iter);
+
+/* initialization, update, destroy */
+void effects_defer_update(void);
+void effects_undefer_update(void);
+void effects_update_all(void);
+void effects_update_all_common(void);
+
+struct effect *append_effect(struct player *pplayer, struct city *home,
+                             struct unit *punit, enum effect_range range);
+void add_nation_effects(struct player *pplayer, bool add_immed_effects);
+void add_tech_effects(struct player *pplayer, int id, bool add_immed_effects);
+void add_government_effects(struct player *pplayer, bool add_immed_effects);
+void add_improvement_effects(struct city *pcity, int id, 
+                             bool add_immed_effects);
+void add_unit_effects(struct unit *punit, bool add_immed_effects);
+
+void delete_effect(struct player *pplayer, struct city *pcity,
+                   struct unit *punit, int id, struct effect_defn *defn);
+void delete_effects(enum effect_class class, struct player *pplayer, 
+                    struct city *pcity, struct unit *punit, int id);
+void delete_effects_common(enum effect_class class, struct player *pplayer, 
+                    struct city *pcity, struct unit *punit, int id);
+
+void allot_island_effects(void);
+
+/* packet conversion */
+void effect_defn_vector_to_array(const struct effect_defn_vector *vector,
+                                struct effect_defn *array, int *array_count);
+void effect_defn_array_to_vector(const struct effect_defn *array,
+                                int array_count,
+                                struct effect_defn_vector *vector);
+
+/* useful iterators */
+
+/* search for effects affecting a particular improvement */
+#define improvement_effects_iterate(_pcity, _id, _type, _eff)               \
+{                                                                           \
+  struct effect_iter _iter;                                                 \
+  struct effect *(_eff);                                                    \
+  struct player *_plr;                                                      \
+                                                                            \
+  assert(_pcity);                                                           \
+  _plr = city_owner(_pcity);                                                \
+  effect_iterator_init(&_iter, _plr, (_pcity), NULL, (_id), (_type));       \
+  while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {                
+
+#define improvement_effects_iterate_end                                     \
+  }                                                                         \
+}
+
+/* search for effects affecting a particular city */
+#define city_effects_iterate(_pcity, _type, _eff)                           \
+  improvement_effects_iterate((_pcity), B_ALL, (_type), (_eff))
+
+#define city_effects_iterate_end                                            \
+  improvement_effects_iterate_end
+
+/* search for effects affecting a particular player */
+#define player_effects_iterate(_player, _type, _eff)                        \
+{                                                                           \
+  struct effect_iter _iter;                                                 \
+  struct effect *(_eff);                                                    \
+  effect_iterator_init(&_iter, (_player), NULL, NULL, B_ALL, (_type));      \
+  while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {                
+
+#define player_effects_iterate_end                                          \
+  }                                                                         \
+}
+
+/* search for effects affecting everyone */
+#define global_effects_iterate(_type, _eff)                                 \
+  player_effects_iterate(NULL, (_type), (_eff))
+
+#define global_effects_iterate_end                                          \
+  player_effects_iterate_end
+
+/* search for effects affecting a particular unit */
+#define unit_effects_iterate(_punit, _type, _eff)                           \
+{                                                                           \
+  struct effect_iter _iter;                                                 \
+  struct effect *(_eff);                                                    \
+  struct player *_plr;                                                      \
+                                                                            \
+  assert(_punit);                                                           \
+  _plr = unit_owner(_punit);                                                \
+  effect_iterator_init(&_iter, _plr, NULL, (_punit), B_ALL, (_type));       \
+  while( ((_eff) = effect_iterator_get_next_active(&_iter)) ) {                
 
-bool are_effects_equal(const struct impr_effect *const peff1,
-                      const struct impr_effect *const peff2);
+#define unit_effects_iterate_end                                            \
+  }                                                                         \
+}
 
 #endif  /* FC__EFFECTS_H */
diff -Nur -Xcvs/diff_ignore snap-pre/common/game.c snap-eff/common/game.c
--- snap-pre/common/game.c      2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/game.c      2004-03-05 20:50:10.000000000 -0600
@@ -254,6 +254,8 @@
   game.occupychance= GAME_DEFAULT_OCCUPYCHANCE;
   game.revolution_length = GAME_DEFAULT_REVOLUTION_LENGTH;
 
+  effect_vector_init(&game.effects);
+
   game.heating     = 0;
   game.cooling     = 0;
 
@@ -336,8 +338,14 @@
 ***************************************************************/
 void game_free(void)
 {
+  effect_vector_free(&game.effects);
   game_remove_all_players();
   map_free();
+
+  /* reinitialize internal variables */
+  map.num_continents = 0;
+  allot_island_effects();
+
   idex_free();
   ruleset_data_free();
   cm_free();
@@ -440,16 +448,27 @@
 ***************************************************************/
 void game_remove_player(struct player *pplayer)
 {
+  int i;
+
   if (pplayer->attribute_block.data) {
     free(pplayer->attribute_block.data);
     pplayer->attribute_block.data = NULL;
   }
 
+  effect_vector_free(&pplayer->effects);
+
   if (pplayer->island_improv) {
     free(pplayer->island_improv);
     pplayer->island_improv = NULL;
   }
 
+  if (pplayer->island_effects) {
+    for (i = 1; i <= map.num_continents; i++) {
+      effect_vector_free(&pplayer->island_effects[i]);
+    }
+    pplayer->island_effects = NULL;
+  }
+
   conn_list_unlink_all(&pplayer->connections);
 
   unit_list_iterate(pplayer->units, punit) 
diff -Nur -Xcvs/diff_ignore snap-pre/common/game.h snap-eff/common/game.h
--- snap-pre/common/game.h      2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/game.h      2004-03-05 20:44:46.000000000 -0600
@@ -20,6 +20,7 @@
 #endif
 
 #include "connection.h"                /* struct conn_list */
+#include "effects.h"
 #include "improvement.h"       /* Impr_Status */
 #include "player.h"
 #include "shared.h"
@@ -108,6 +109,7 @@
          /* global_wonders[] may also be (-1), or the id of a city
            which no longer exists, if the wonder has been destroyed */
   Impr_Status improvements[B_LAST];        /* impr. with equiv_range==World */
+  struct effect_vector effects;                   /* effects with 
range==global */
 
   int heating; /* Number of polluted squares. */
   int globalwarming; /* Total damage done. (counts towards a warming event.) */
diff -Nur -Xcvs/diff_ignore snap-pre/common/government.h 
snap-eff/common/government.h
--- snap-pre/common/government.h        2003-07-04 06:20:45.000000000 -0500
+++ snap-eff/common/government.h        2004-03-05 20:44:46.000000000 -0600
@@ -13,6 +13,7 @@
 #ifndef FC__GOVERNMENT_H
 #define FC__GOVERNMENT_H
 
+#include "effects.h"
 #include "shared.h"
 
 struct city;
@@ -152,6 +153,8 @@
   int   hints;
 
   struct Sprite *sprite;
+
+  struct effect_defn_vector effect_defs;
   
   char *helptext;
 };
diff -Nur -Xcvs/diff_ignore snap-pre/common/improvement.c 
snap-eff/common/improvement.c
--- snap-pre/common/improvement.c       2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/improvement.c       2004-03-05 20:44:46.000000000 -0600
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include "effects.h"
 #include "game.h"
 #include "log.h"
 #include "map.h"
@@ -100,8 +101,7 @@
   free(p->equiv_repl);
   p->equiv_repl = NULL;
 
-  free(p->effect);
-  p->effect = NULL;
+  effect_defn_vector_free(&(p->effect_defs));
 
   free(p->helptext);
   p->helptext = NULL;
@@ -346,6 +346,9 @@
 /**************************************************************************
   Whether player could build this improvement, assuming they had
   the tech req, and assuming a city with the right pre-reqs etc.
+
+  FIXME: this will not work correctly with a general effects paradigm.
+  We must pass in a city if there is one.
 **************************************************************************/
 bool could_player_eventually_build_improvement(struct player *p,
                                              Impr_Type_id id)
@@ -358,28 +361,51 @@
 
   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;
+  /* we have some special rules for space parts.  */
+  effect_defn_vector_iterate(impr->effect_defs, defn) {
+    /* is this improvement considered a space part? */
+    if (defn->type == EFT_SPACE_PART) {
+      bool space_enabled = FALSE;
+
+      /* if spaceship is already launched, can't build it */
+      if (p->spaceship.state >= SSHIP_LAUNCHED) {
+        return FALSE;
+      }
+
+      /* we can't build it though unless we feel the "Enable_Space" effect */
+      player_effects_iterate(p, EFT_ENABLE_SPACE, eff) {
+        space_enabled = TRUE;
+        break;
+      } player_effects_iterate_end;
+  
+      if (!space_enabled) {
+        return FALSE;
+      }
+
+      /* ok, we can go to space, but we still can't build 
+       * it if we've already built too many... amounts are
+       * special-cased, defined here. */
+      switch (defn->amount) {
+      case 1:
+        if (p->spaceship.structurals >= NUM_SS_STRUCTURALS) {
+          return FALSE;
+        }
+        break;
+      case 2:
+        if (p->spaceship.components >= NUM_SS_COMPONENTS) {
+          return FALSE;
+        }
+        break;
+      case 3:
+      default: /* treat > 3 to be 3. */
+        if (p->spaceship.modules >= NUM_SS_MODULES) {
+          return FALSE;
+        }
+        break;
       }
-      peffect++;
     }
-  }
+  } effect_defn_vector_iterate_end;
+
   if (is_wonder(id)) {
     /* Can't build wonder if already built */
     if (game.global_wonders[id] != 0) return FALSE;
@@ -464,13 +490,17 @@
       Impr_Status *improvs = 
                            &pplayer->island_improv[cont * game.num_impr_types];
 
-      built_impr_iterate(pcity, id) {
+      impr_type_iterate(id) {
+        if (pcity->improvements[id] == I_NONE) {
+          continue;
+        }
+
         if (improvement_types[id].equiv_range != IR_ISLAND) {
           continue;
         }
     
         improvs[id] = pcity->improvements[id];
-      } built_impr_iterate_end;
+      } impr_type_iterate_end;
     } city_list_iterate_end;
   } players_iterate_end;
 
diff -Nur -Xcvs/diff_ignore snap-pre/common/improvement.h 
snap-eff/common/improvement.h
--- snap-pre/common/improvement.h       2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/improvement.h       2004-03-05 20:44:46.000000000 -0600
@@ -32,7 +32,6 @@
 #define I_OBSOLETE   2   /* Built, but obsoleted by a tech */
 #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
 
@@ -64,6 +63,7 @@
  * it can also be used for fixed allocations to ensure ability
  * to hold full number of improvement types.  */
 #define B_LAST MAX_NUM_ITEMS
+#define B_ALL B_LAST
 
 /* Range of equivalence (used in equiv_range fields)
  * These must correspond to impr_range_names[] in improvement.c. */
@@ -76,25 +76,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 */
-  enum tile_terrain_type aff_terr; /* T_UNKNOWN = all; T_LAST = 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];
@@ -113,8 +94,9 @@
   int build_cost;                      /* Use wrappers to access this. */
   int upkeep;
   int sabotage;
-  struct impr_effect *effect;          /* list; .type==EFT_LAST terminated */
-  int variant;                 /* FIXME: remove when gen-impr obsoletes */
+  struct effect_defn_vector effect_defs;        /* list of effect definitions 
*/
+  int variant;                     /* FIXME: remove when gen-impr obsoletes */
+
   struct Sprite *sprite;               /* icon of the improvement */
   char *helptext;
   char soundtag[MAX_LEN_NAME];
diff -Nur -Xcvs/diff_ignore snap-pre/common/nation.h snap-eff/common/nation.h
--- snap-pre/common/nation.h    2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/nation.h    2004-03-05 20:44:46.000000000 -0600
@@ -13,6 +13,7 @@
 #ifndef FC__NATION_H
 #define FC__NATION_H
 
+#include "effects.h"
 #include "shared.h"            /* MAX_LEN_NAME */
 #include "terrain.h"           /* T_COUNT */
 
@@ -99,6 +100,8 @@
     int wonder;                                 /* primary Wonder */
     int government;
   } goals;
+
+  struct effect_defn_vector effect_defs;
 };
 
 struct team {
diff -Nur -Xcvs/diff_ignore snap-pre/common/packets.def 
snap-eff/common/packets.def
--- snap-pre/common/packets.def 2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/packets.def 2004-03-05 20:51:16.000000000 -0600
@@ -157,7 +157,7 @@
 type CITY_MAP          = city_map(char)
 type WORKLIST          = worklist(struct worklist)
 type TECH_LIST         = tech_list(int)
-type EFFECT            = effect(struct impr_effect)
+type EFFECT_DEFN        = effect_defn(struct effect_defn)
 
 # typedefs for enums
 type CLAUSE            = uint8(enum clause_type)
@@ -947,6 +947,8 @@
 
   bitvector(bv_flags) flags;
   bitvector(bv_roles) roles;
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 end
 
 PACKET_RULESET_GAME=97;sc
@@ -963,6 +965,8 @@
   UINT8 tech_cost_style;
   UINT8 tech_leakage;
   TECH_LIST global_init_techs[MAX_NUM_TECH_LIST];
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 
   UINT8 trireme_loss_chance[MAX_VET_LEVELS]; add-cap(veteran)
   UINT8 work_veteran_chance[MAX_VET_LEVELS]; add-cap(veteran)
@@ -986,6 +990,8 @@
   STRING helptext[MAX_LEN_PACKET];
   STRING graphic_str[MAX_LEN_NAME];
   STRING graphic_alt[MAX_LEN_NAME];
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 end
 
 PACKET_RULESET_GOVERNMENT=100;sc
@@ -1049,6 +1055,8 @@
   STRING graphic_str[MAX_LEN_NAME];
   STRING graphic_alt[MAX_LEN_NAME];
   STRING helptext[MAX_LEN_PACKET];
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 end
 
 PACKET_RULESET_TERRAIN_CONTROL=101;sc
@@ -1096,6 +1104,8 @@
   UINT8 leader_count;
   STRING leader_name[MAX_NUM_LEADERS:leader_count][MAX_LEN_NAME];
   BOOL leader_sex[MAX_NUM_LEADERS:leader_count];
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 end
 
 PACKET_RULESET_CITY=103;sc
@@ -1132,8 +1142,8 @@
   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];  
+  UINT8 effect_defs_count;
+  EFFECT_DEFN effect_defs[255:effect_defs_count];
 end
 
 PACKET_RULESET_TERRAIN=105;sc
@@ -1214,3 +1224,9 @@
 
   STRING team_name[MAX_NUM_TEAMS][MAX_LEN_NAME];
 end
+
+PACKET_GLOBAL_EFFECT=107;sc
+  BOOL add_effect;                       /* if FALSE, remove the effect */
+  PLAYER player;
+  EFFECT_DEFN effect_def[1];
+end
diff -Nur -Xcvs/diff_ignore snap-pre/common/player.c snap-eff/common/player.c
--- snap-pre/common/player.c    2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/player.c    2004-03-05 20:44:46.000000000 -0600
@@ -131,18 +131,26 @@
   plr->gives_shared_vision = 0;
   plr->really_gives_vision = 0;
 
-  /* Initialise list of improvements with Player-wide equiv_range */
+  /* Initialise list of improvements and effects with Player-wide range */
   improvement_status_init(plr->improvements, ARRAY_SIZE(plr->improvements));
+  effect_vector_init(&plr->effects);
 
-  /* Initialise list of improvements with Island-wide equiv_range */
+  /* Initialise list of improvements and effects with Island-wide range */
   plr->island_improv = NULL;
+  plr->island_effects = NULL;
 
   if (map.num_continents > 0) {
     plr->island_improv = fc_malloc((map.num_continents + 1) * 
                                    game.num_impr_types * sizeof(Impr_Status));
+
+    plr->island_effects = fc_malloc((map.num_continents + 1) *
+                                    sizeof(struct effect_vector));
+
     for (i = 1; i <= map.num_continents; i++) {
       improvement_status_init(&plr->island_improv[i * game.num_impr_types],
                               game.num_impr_types);
+
+      effect_vector_init(&plr->island_effects[i]);
     }
   }
 
diff -Nur -Xcvs/diff_ignore snap-pre/common/player.h snap-eff/common/player.h
--- snap-pre/common/player.h    2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/common/player.h    2004-03-05 20:44:46.000000000 -0600
@@ -15,6 +15,7 @@
 
 #include "city.h"
 #include "connection.h"
+#include "effects.h"
 #include "improvement.h"       /* Impr_Status */
 #include "nation.h"
 #include "shared.h"
@@ -209,6 +210,8 @@
   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 effect_vector effects;         /* effects with range==Player */
+  struct effect_vector *island_effects; /* effects with range==Island */
 
   bool can_nuke;        /* bits to record the two effects which survive */
   bool can_space;       /* their origin's destruction. */
diff -Nur -Xcvs/diff_ignore snap-pre/common/specvec.h snap-eff/common/specvec.h
--- snap-pre/common/specvec.h   2003-08-07 22:42:16.000000000 -0500
+++ snap-eff/common/specvec.h   2004-03-05 20:44:46.000000000 -0600
@@ -66,9 +66,9 @@
 
 void SPECVEC_FOO(_vector_init) (SPECVEC_VECTOR *tthis);
 void SPECVEC_FOO(_vector_reserve) (SPECVEC_VECTOR *tthis, int n);
-size_t SPECVEC_FOO(_vector_size) (SPECVEC_VECTOR *tthis);
-SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (SPECVEC_VECTOR *tthis, int index);
-void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, SPECVEC_VECTOR *from);
+size_t SPECVEC_FOO(_vector_size) (const SPECVEC_VECTOR *tthis);
+SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (const SPECVEC_VECTOR *tthis, int 
index);
+void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, const SPECVEC_VECTOR 
*from);
 void SPECVEC_FOO(_vector_free) (SPECVEC_VECTOR *tthis);
 
 #undef SPECVEC_TAG
diff -Nur -Xcvs/diff_ignore snap-pre/common/specvec_c.h 
snap-eff/common/specvec_c.h
--- snap-pre/common/specvec_c.h 2003-08-07 22:45:00.000000000 -0500
+++ snap-eff/common/specvec_c.h 2004-03-05 20:44:46.000000000 -0600
@@ -51,12 +51,12 @@
   ath_minnum(&tthis->vector, n);
 }
 
-size_t SPECVEC_FOO(_vector_size) (SPECVEC_VECTOR *tthis)
+size_t SPECVEC_FOO(_vector_size) (const SPECVEC_VECTOR *tthis)
 {
   return tthis->vector.n;
 }
 
-SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (SPECVEC_VECTOR *tthis, int index)
+SPECVEC_TYPE *SPECVEC_FOO(_vector_get) (const SPECVEC_VECTOR *tthis, int index)
 {
   assert(index>=0 && index<tthis->vector.n);
 
@@ -64,7 +64,7 @@
 }
 
 /* You must _init "*to" before using this function */
-void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, SPECVEC_VECTOR *from)
+void SPECVEC_FOO(_vector_copy) (SPECVEC_VECTOR *to, const SPECVEC_VECTOR *from)
 {
   int i;
   size_t size = SPECVEC_FOO(_vector_size) (from);
diff -Nur -Xcvs/diff_ignore snap-pre/common/tech.c snap-eff/common/tech.c
--- snap-pre/common/tech.c      2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/tech.c      2004-03-05 20:44:46.000000000 -0600
@@ -57,7 +57,7 @@
 ...
 **************************************************************************/
 void set_invention(struct player *pplayer, Tech_Type_id tech,
-                  enum tech_state value)
+                  enum tech_state value, bool add_immed_effects)
 {
   if (pplayer->research.inventions[tech].state == value) {
     return;
@@ -68,6 +68,7 @@
   if (value == TECH_KNOWN) {
     game.global_advances[tech]++;
     improvements_update_obsolete();
+    add_tech_effects(pplayer, tech, add_immed_effects);
   }
 }
 
@@ -194,16 +195,16 @@
 
   tech_type_iterate(i) {
     if (!tech_is_available(pplayer, i)) {
-      set_invention(pplayer, i, TECH_UNKNOWN);
+      set_invention(pplayer, i, TECH_UNKNOWN, FALSE);
     } else {
       if (get_invention(pplayer, i) == TECH_REACHABLE) {
-       set_invention(pplayer, i, TECH_UNKNOWN);
+       set_invention(pplayer, i, TECH_UNKNOWN, FALSE);
       }
 
       if (get_invention(pplayer, i) == TECH_UNKNOWN
          && get_invention(pplayer, advances[i].req[0]) == TECH_KNOWN
          && get_invention(pplayer, advances[i].req[1]) == TECH_KNOWN) {
-       set_invention(pplayer, i, TECH_REACHABLE);
+       set_invention(pplayer, i, TECH_REACHABLE, FALSE);
       }
     }
     build_required_techs(pplayer, i);
diff -Nur -Xcvs/diff_ignore snap-pre/common/tech.h snap-eff/common/tech.h
--- snap-pre/common/tech.h      2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/tech.h      2004-03-05 20:44:46.000000000 -0600
@@ -14,6 +14,7 @@
 #define FC__TECH_H
 
 #include "shared.h"
+#include "effects.h"
 
 #include "nation.h" /* Nation_Type_id */
 
@@ -103,13 +104,15 @@
    * itself. Precalculated at server then send to client.
    */
   int num_reqs;
+
+  struct effect_defn_vector effect_defs;
 };
 
 BV_DEFINE(tech_vector, A_LAST);
 
 enum tech_state get_invention(struct player *pplayer, Tech_Type_id tech);
 void set_invention(struct player *pplayer, Tech_Type_id tech,
-                  enum tech_state value);
+                  enum tech_state value, bool add_immed_effects);
 void update_research(struct player *pplayer);
 Tech_Type_id get_next_tech(struct player *pplayer, Tech_Type_id goal);
 
diff -Nur -Xcvs/diff_ignore snap-pre/common/unit.c snap-eff/common/unit.c
--- snap-pre/common/unit.c      2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/unit.c      2004-03-05 20:52:50.000000000 -0600
@@ -1512,6 +1512,10 @@
   punit->occupy = 0;
   punit->has_orders = FALSE;
 
+  /* Initialise unit's vector of improvement effects. */
+  effect_vector_init(&punit->effects);
+  add_unit_effects(punit, TRUE);
+
   return punit;
 }
 
@@ -1522,6 +1526,9 @@
 void destroy_unit_virtual(struct unit *punit)
 {
   free_unit_orders(punit);
+
+  effect_vector_free(&punit->effects);
+
   free(punit);
 }
 
diff -Nur -Xcvs/diff_ignore snap-pre/common/unit.h snap-eff/common/unit.h
--- snap-pre/common/unit.h      2004-02-22 11:12:03.000000000 -0600
+++ snap-eff/common/unit.h      2004-03-05 20:53:16.000000000 -0600
@@ -162,6 +162,8 @@
   int transported_by;
   int occupy; /* number of units that occupy transporter */
 
+  struct effect_vector effects;
+
   bool has_orders;
   struct {
     int length, index;
diff -Nur -Xcvs/diff_ignore snap-pre/common/unittype.h 
snap-eff/common/unittype.h
--- snap-pre/common/unittype.h  2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/common/unittype.h  2004-03-05 20:44:46.000000000 -0600
@@ -14,6 +14,7 @@
 #define FC__UNITTYPE_H
 
 #include "shared.h"
+#include "effects.h"
 
 struct player;
 struct city;
@@ -196,6 +197,8 @@
   bv_flags flags;
   bv_roles roles;
 
+  struct effect_defn_vector effect_defs;  /* list of effect definitions */
+
   int happy_cost;  /* unhappy people in home city */
   int shield_cost; /* normal upkeep cost */
   int food_cost;   /* settler food cost */
diff -Nur -Xcvs/diff_ignore snap-pre/data/default/units.ruleset 
snap-eff/data/default/units.ruleset
--- snap-pre/data/default/units.ruleset 2004-02-22 11:12:04.000000000 -0600
+++ snap-eff/data/default/units.ruleset 2004-03-05 20:44:46.000000000 -0600
@@ -85,6 +85,7 @@
 ;                (NOTE: gold upkeep is still not implemented)
 ; flags         = special flag strings
 ; roles         = special role strings
+; effect        = effects that this unit has. see doc/README.effects
 ; sound_move   = optional sound effect when the unit moves
 ; sound_move_alt= optional alternative sound effect if above not
 ;                supported in client
@@ -206,6 +207,14 @@
 uk_gold       = 0
 flags         = "Settlers", "NonMil", "Airbase", "AddToCity", "Cities", 
"NoVeteran"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Settlers"
+       "Unit_Nonmilitary"
+       "Unit_Airbase"
+       "Unit_Add_To_City"
+       "Unit_Cities"
+    }
 helptext      = _("\
 Settlers are one of the key units in the game.  They can be used to\
  found new cities, irrigate land, build roads, railroads,\
@@ -250,6 +259,15 @@
 uk_gold       = 0
 flags         = "Settlers", "NonMil", "Transform", "Airbase", "AddToCity", 
"Cities", "NoVeteran"
 roles         = ""
+effect        =
+    { "type"
+        "Unit_Settlers"
+        "Unit_Nonmilitary"
+       "Unit_Transform"
+        "Unit_Airbase"
+        "Unit_Add_To_City"
+        "Unit_Cities"
+    }
 helptext      = _("\
 Engineers are similar to Settlers, but they work twice as fast and\
  move twice as fast.  Engineers may also perform major terrain\
@@ -407,6 +425,10 @@
 uk_gold       = 0
 flags         = "Pikemen"
 roles         = "DefendGood", "FirstBuild"
+effect        =
+    { "type"
+       "Unit_Pikemen"
+    }
 
 [unit_musketeers]
 name          = _("Musketeers")
@@ -492,6 +514,11 @@
 uk_gold       = 0
 flags         = "IgTer", "IgZOC"
 roles         = "DefendGood", "Partisan", "BarbarianTech"
+effect        =
+    { "type"
+       "Unit_Ignore_Terrain"
+       "Unit_Ignore_ZOC"
+    }
 helptext      = _("\
 A number of Partisans are granted free when an enemy conquers your\
  city, but only under these conditions:\
@@ -532,6 +559,10 @@
 uk_gold       = 0
 flags         = "IgTer"
 roles         = "DefendGood"
+effect        =
+    { "type"
+       "Unit_Ignore_Terrain"
+    }
 
 [unit_riflemen]
 name          = _("Riflemen")
@@ -588,6 +619,10 @@
 uk_gold       = 0
 flags         = "Marines"
 roles         = "DefendOk", "BarbarianSeaTech"
+effect        =
+    { "type"
+       "Unit_Marines"
+    }
 
 [unit_paratroopers]
 name          = _("Paratroopers")
@@ -620,6 +655,10 @@
 paratroopers_range = 10
 paratroopers_mr_req = 1
 paratroopers_mr_sub = 0
+effect        =
+    { "type", "amount", "value1", "value2"
+       "Unit_Paratroopers", 10, 1, 0
+    }
 
 [unit_mech_inf]
 name          = _("Mech. Inf.")
@@ -681,6 +720,10 @@
 uk_gold       = 0
 flags         = "Horse"
 roles         = "AttackFast", "Hut", "Barbarian"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_chariot]
 name          = _("Chariot")
@@ -709,6 +752,10 @@
 uk_gold       = 0
 flags         = "Horse"
 roles         = "AttackFast", "Hut"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_elephants]
 name          = _("Elephants")
@@ -737,6 +784,10 @@
 uk_gold       = 0
 flags         = "Horse"
 roles         = "AttackFast"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_crusaders]
 name          = _("Crusaders")
@@ -765,6 +816,10 @@
 uk_gold       = 0
 flags         = "Horse"
 roles         = "AttackFast"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_knights]
 name          = _("Knights")
@@ -794,6 +849,10 @@
 flags         = "Horse"
 roles         = "AttackFast", "HutTech", "BarbarianTech",
                 "BarbarianBuildTech", "BarbarianSeaTech"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_dragoons]
 name          = _("Dragoons")
@@ -822,6 +881,10 @@
 uk_gold       = 0
 flags         = "Horse"
 roles         = "AttackFast", "BarbarianBuildTech", "BarbarianSeaTech"
+effect        =
+    { "type"
+       "Unit_Horse"
+    }
 
 [unit_cavalry]
 name          = _("Cavalry")
@@ -990,6 +1053,10 @@
 uk_gold       = 0
 flags         = "IgWall"
 roles         = "AttackStrong"
+effect        =
+    { "type"
+       "Unit_Ignore_Walls"
+    }
 
 [unit_fighter]
 name          = _("Fighter")
@@ -1018,6 +1085,10 @@
 uk_gold       = 0
 flags         = "Fighter"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Fighter"
+    }
 
 [unit_bomber]
 name          = _("Bomber")
@@ -1046,6 +1117,11 @@
 uk_gold       = 0
 flags         = "FieldUnit", "OneAttack"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Field_Unit"
+       "Unit_One_Attack"
+    }
 
 [unit_helicopter]
 name          = _("Helicopter")
@@ -1074,6 +1150,11 @@
 uk_gold       = 0
 flags         = "FieldUnit", "OneAttack"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Field_Unit"
+       "Unit_One_Attack"
+    }
 helptext      = _("\
 The Helicopter is a very powerful unit, as it can both fly and\
  conquer cities.  Care must be exercised, because Helicopters lose a\
@@ -1108,6 +1189,11 @@
 uk_gold       = 0
 flags         = "Partial_Invis", "Fighter"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Partial_Invisible"
+       "Unit_Fighter"
+    }
 helptext      = _("\
 An improved Fighter, with improved attack and a higher movement\
  radius.\
@@ -1140,6 +1226,12 @@
 uk_gold       = 0
 flags         = "Partial_Invis", "FieldUnit", "OneAttack"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Partial_Invisible"
+       "Unit_Field_Unit"
+       "Unit_Fighter"
+    }
 helptext      = _("\
 An improved Bomber, with improved attack and a higher movement\
  radius.\
@@ -1172,6 +1264,10 @@
 uk_gold       = 0
 flags         = "Trireme"
 roles         = "Ferryboat"
+effect        =
+    { "type"
+       "Unit_Trireme"
+    }
 
 [unit_caravel]
 name          = _("Caravel")
@@ -1372,6 +1468,10 @@
 uk_gold       = 0
 flags         = "AEGIS"
 roles         = "DefendGood"
+effect        =
+    { "type"
+       "Unit_AEGIS"
+    }
 
 [unit_battleship]
 name          = _("Battleship")
@@ -1429,6 +1529,12 @@
 flags         = "Partial_Invis", 
                "Missile_Carrier", "No_Land_Attack"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Partial_Invisible"
+       "Unit_Missile_Carrier"
+       "Unit_No_Land_Attack"
+    }
 helptext      = _("\
 Submarines have a very high strategic value, but have a weak\
  defence.\
@@ -1461,6 +1567,10 @@
 uk_gold       = 0
 flags         = "Carrier"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Carrier"
+    }
 helptext      = _("\
 TIP:  Guard Carriers with a handful of fast-moving ships and a\
  battleship, as losing a fully-equipped Carrier is VERY\
@@ -1522,6 +1632,12 @@
 uk_gold       = 0
 flags         = "FieldUnit", "OneAttack", "Missile"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Field_Unit"
+       "Unit_One_Attack"
+       "Unit_Missile"
+    }
 helptext      = _("\
 TIP:  A handful of these can successfully keep the waters around\
  your treasured homeland free of enemy ships.\
@@ -1554,6 +1670,13 @@
 uk_gold       = 0
 flags         = "FieldUnit", "OneAttack", "Missile", "Nuclear"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Field_Unit"
+       "Unit_One_Attack"
+       "Unit_Missile"
+       "Unit_Nuclear"
+    }
 helptext      = _("\
 You can build Nuclear units when you have the required advance, and\
  the Manhattan Project wonder has been built by any player.\
@@ -1601,6 +1724,12 @@
 uk_gold       = 0
 flags         = "Diplomat", "IgZOC", "NonMil"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Diplomat"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary" 
+    }
 helptext      = _("\
 - A Diplomat can establish embassies with other civilizations\
  by moving into another player's city.\
@@ -1647,6 +1776,13 @@
 uk_gold       = 0
 flags         = "Diplomat", "IgZOC", "NonMil", "Spy"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Diplomat"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary"
+       "Unit_Spy"
+    }
 helptext      = _("\
 A Spy is a full time professional and as such is much more\
  skilled in the arts of espionage than her Diplomat predecessor.\
@@ -1694,6 +1830,13 @@
 uk_gold       = 0
 flags         = "TradeRoute", "HelpWonder", "IgZOC", "NonMil"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Trade_Route"
+       "Unit_Help_Wonder"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary"
+    }
 helptext      = _("\
 Every Caravan that is used to build a wonder will add 50 shields\
  towards the production of the wonder.\
@@ -1730,6 +1873,13 @@
 uk_gold       = 0
 flags         = "TradeRoute", "HelpWonder", "IgZOC", "NonMil"
 roles         = ""
+effect        =
+    { "type"
+       "Unit_Trade_Route"
+       "Unit_Help_Wonder"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary"
+    }
 helptext      = _("\
 The Freight unit replaces the Caravan, and moves at twice the speed.\
 ")
@@ -1761,6 +1911,12 @@
 uk_gold       = 0
 flags         = "IgTer", "IgZOC", "NonMil"
 roles         = "Explorer"
+effect        =
+    { "type"
+       "Unit_Ignore_Terrain"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary"
+    }
 helptext      = _("\
 Explorers are very useful for mapping unknown territory.\
 ")
@@ -1793,6 +1949,17 @@
 flags         = "IgZOC", "NonMil", "Unbribable",
                 "Undisbandable", "SuperSpy", "NoHome"
 roles         = "BarbarianLeader"
+effect        =
+    { "type"
+       "Unit_Ignore_ZOC"
+       "Unit_Nonmilitary"
+       "Unit_Game_Loss"
+       "Unit_Unique"
+       "Unit_Unbribable"
+       "Unit_Undisbandable"
+       "Unit_Super_Spy"
+       "Unit_No_Home"
+    }
 helptext      = _("\
 When barbarian leader is killed on a tile without any defending units, \
 the 100 gold ransom is paid, but only to land units and helicopters.\
diff -Nur -Xcvs/diff_ignore snap-pre/doc/README.effects 
snap-eff/doc/README.effects
--- snap-pre/doc/README.effects 2003-09-30 18:20:42.000000000 -0500
+++ snap-eff/doc/README.effects 2004-03-05 20:44:46.000000000 -0600
@@ -274,14 +274,121 @@
 
 "Upkeep_Free"  - improvements with AMOUNT or less upkeep cost become
                  free to upkeep (others are unaffected)
+__________________________________________________________________________
+The effects below are strictly unit effects.
 
-.range may be one of: 
- "None", "Local", "City", "Island", "Player", "World"
+"Unit_Add_To_City" - can disband to add a single point of population to a city
+                 (see cities.ruleset for limitation of this ability)
 
+"Unit_AEGIS"   - fivefold increased defence against air attacks and missiles
+
+"Unit_Airbase" - (land only) can produce airbases
+
+"Unit_Carrier" - can transport air and missile units, but not land units
+
+"Unit_Cities" - can disband to produce a city
+
+"Unit_Diplomat" - can do diplomat actions (see diplchance server option)
+
+"Unit_Fanatic" - can only be built by governments that allow them
+                 (see data/civ2/governments.ruleset, Fanaticism government)
+
+"Unit_Field_Unit" - cause unhappiness even when not being aggressive
+
+"Unit_Fighter" - can attack air units (no other units can normally do this)
+
+"Unit_Game_Loss" - losing one of these units means you lose the game, but it
+                 is produced without homecity and upkeep
+
+"Unit_Help_Wonder" - can help build wonders
+
+"Unit_Horse"   - (no effect)
+
+"Unit_Ignore_Terrain" - ignore terrain/road/rail, treat every tile as 1/3 
+                 move cost
+
+"Unit_Ignore_Tired" - ignore tired penalty when attacking
+
+"Unit_Ignore_Walls" - ignore effect of city walls
+
+"Unit_Ignore_ZOC" - (land only) ignore Zones of Control (ZOC)
+
+"Unit_Marines" - (land only) can attack from transports
+
+"Unit_Missile" - (air only) some buildings and units have higher defence
+                  against these
+
+"Unit_Missile_Carrier" - can transport only missiles, but no aircraft or 
+                 land units
+
+"Unit_No_Home" - this unit has no homecity and will be free of all upkeep, 
+                 and therefore will not revolt along with its city of 
+                 origin should it be incited
+
+"Unit_No_Land_Attack" - (sea only) cannot attack targets on land
+
+"Unit_Nonmilitary" - a non-military unit, does not cause unhappiness
+
+"Unit_Nuclear" - nuke!
+
+"Unit_One_Attack" - can only make a single attack, regardless of movement 
+                 points
+
+"Unit_Paratroopers" - (land only) can paradrop. the maximal range is AMOUNT.
+                 VALUE1 is the least move rate required for paradropping.
+                 VALUE2 is the move rate which is subtracted after
+                 paradropping
+
+"Unit_Partial_Invisible" - visible only to adjancent units; does not hide 
+                 transported units other than missiles
+
+"Unit_Pikemen" - double defence power against "Horse" flag units
+
+"Unit_Settlers" - can irrigate and build roads
+
+"Unit_Spy"     - can do poison and sabotage, _must_ be "Diplomat" also
+
+"Unit_Trade_Route" - can establish trade routes
+
+"Unit_Transform" - can transform terrain
+
+"Unit_Trireme" - (sea only) sinks on high seas, lots of special rules
+
+"Unit_Unbribable" - this unit cannot be bribed
+
+"Unit_Undisbandable" - this unit cannot be disbanded, will not drown, and 
+                 will not disband due to lack of shields to upkeep it in 
+                 homecity if not given enough food to upkeep it, homecity 
+                 will shrink every turn it cannot do so, however
+
+"Unit_Super_Spy" - this unit always wins diplomatic contests, that is, 
+                 unless it encounters another SuperSpy, in which case 
+                 defender wins; can also be used on non-diplomat units, 
+                 in which case it can protect cities from diplomats; 
+                 also 100% spy survival chance
+
+"Unit_Unique"  - a player can only have one of these units in the game at
+                 the same time; barbarians cannot use this at present
+
+
+
+.range    =  one of: "None", "Local", "City", "Island", "Player", "World"
+.outside   = 1 if, for effects at greater than City-range, the effect
+            is active in all tiles, not just the city center. For tax
+            and science city bonuses, this means that the TOTAL science
+            output of all cities affected is subject to the bonus,
+            rather than the output of each city individually.
+            Applicable effects: Science_Bonus, Science_Pct,
+            Tax_Bonus, Tax_Pct, Unit_Defend, Unit_Attack,
+            Unit_Attack_Firepower, Unit_Defend_Firepower,
+            Unit_Recover, Unit_Vet_Combat, Upgrade_*
+            (if unspecified, 0 (city center only) is assumed)
 .amount           = integral AMOUNT parameter for many effects
            (must be in the range -32767 to 32767)
-.survives  = 1 if effect survives destruction (wonders only)
-           (if unspecified, 0 (doesn't survive) is assumed)
+.value1    = integral VALUE1 parameter for certain effects
+           (must be in the range -32767 to 32767)
+.value2    = integral VALUE2 parameter for certain effects
+           (must be in the range -32767 to 32767)
 .cond_bldg = must have this building in same city for effect
            (if unspecified, effect not conditional on building)
 .cond_nat  = must be this nation for effect
diff -Nur -Xcvs/diff_ignore snap-pre/server/barbarian.c 
snap-eff/server/barbarian.c
--- snap-pre/server/barbarian.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/barbarian.c 2004-03-07 17:04:47.000000000 -0600
@@ -113,6 +113,7 @@
 
   /* make a new player */
 
+  player_init(barbarians); /* need to do this here to init island effects */
   server_player_init(barbarians, TRUE);
 
   barbarians->nation = game.nation_count - 1;
diff -Nur -Xcvs/diff_ignore snap-pre/server/citytools.c 
snap-eff/server/citytools.c
--- snap-pre/server/citytools.c 2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/citytools.c 2004-03-05 20:44:46.000000000 -0600
@@ -877,7 +877,7 @@
 
   pnew_capital = city_list_get(&pplayer->cities, myrand(size));
 
-  city_add_improvement(pnew_capital, B_PALACE);
+  city_add_improvement(pnew_capital, B_PALACE, TRUE);
 
   /*
    * send_player_cities will recalculate all cities and send them to
@@ -1010,10 +1010,15 @@
   if (raze)
     raze_city(pcity);
 
-  /* Restore any global improvement effects that this city confers */
+  /* Restore any global improvement effects that this city confers 
+   * do not add immediate effects as they occurred when the impr was built */
+  effects_defer_update();
   built_impr_iterate(pcity, i) {
-    city_add_improvement(pcity, i);
+    city_add_improvement(pcity, i, FALSE);
   } built_impr_iterate_end;
+  effects_undefer_update();
+  freelog(LOG_VERBOSE, "%%%%%%%%: transfer city"); /* DEBUGGING/REMOVE */
+  effects_update_all();
 
   /* Set production to something valid for pplayer, if not. */
   if ((pcity->is_building_unit
@@ -1084,7 +1089,7 @@
 
   if (!pplayer->capital) {
     pplayer->capital = TRUE;
-    city_add_improvement(pcity, B_PALACE);
+    city_add_improvement(pcity, B_PALACE, TRUE);
   }
 
   /* Before arranging workers to show unknown land */
@@ -1181,10 +1186,17 @@
      and to handle the preservation of "destroyed" effects. */
   effect_update=FALSE;
 
+  effects_defer_update();
   built_impr_iterate(pcity, i) {
     effect_update = TRUE;
     city_remove_improvement(pcity, i);
   } built_impr_iterate_end;
+  effects_undefer_update();
+
+  if (effect_update) {
+    freelog(LOG_VERBOSE, "%%%%%%%%: remove city"); /* DEBUGGING/REMOVE */
+    effects_update_all();
+  }
 
   /* This is cutpasted with modifications from transfer_city_units. Yes, it is 
ugly.
      But I couldn't see a nice way to make them use the same code */
@@ -1738,13 +1750,7 @@
       *p++=get_worker_city(pcity, x, y)+'0';
   *p='\0';
 
-  p=packet->improvements;
-
-  impr_type_iterate(i) {
-    *p++ = (city_got_building(pcity, i)) ? '1' : '0';
-  } impr_type_iterate_end;
-
-  *p='\0';
+  sz_strlcpy(packet->improvements, pcity->improvements);
 }
 
 /**************************************************************************
diff -Nur -Xcvs/diff_ignore snap-pre/server/cityturn.c 
snap-eff/server/cityturn.c
--- snap-pre/server/cityturn.c  2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/cityturn.c  2004-03-05 20:44:46.000000000 -0600
@@ -114,6 +114,8 @@
   struct player *pplayer = city_owner(pcity);
   bool sold = FALSE;
 
+  effects_defer_update();
+
   built_impr_iterate(pcity, i) {
     if (!is_wonder(i) && improvement_obsolete(pplayer, i)) {
       do_sell_building(pplayer, pcity, i);
@@ -125,6 +127,13 @@
     }
   } built_impr_iterate_end;
 
+  effects_undefer_update();
+
+  if (sold) {
+    freelog(LOG_VERBOSE, "%%%%%%%%: removing obsolete"); /* DEBUGGING/REMOVE */
+    effects_update_all();
+  }
+
   if (sold && refresh) {
     city_refresh(pcity);
     send_city_info(pplayer, pcity);
@@ -945,7 +954,7 @@
       pplayer->spaceship.modules++;
     } else {
       space_part = FALSE;
-      city_add_improvement(pcity, pcity->currently_building);
+      city_add_improvement(pcity, pcity->currently_building, TRUE);
     }
     pcity->before_change_shields -=
        impr_build_shield_cost(pcity->currently_building);
diff -Nur -Xcvs/diff_ignore snap-pre/server/gamehand.c 
snap-eff/server/gamehand.c
--- snap-pre/server/gamehand.c  2003-12-14 18:20:53.000000000 -0600
+++ snap-eff/server/gamehand.c  2004-03-05 20:44:46.000000000 -0600
@@ -17,6 +17,7 @@
 
 #include <assert.h>
 
+#include "effects.h"
 #include "events.h"
 #include "fcintl.h"
 #include "improvement.h"
@@ -366,3 +367,132 @@
 
   return game.timeout;
 }
+
+#include <stdio.h> /* DEBUGGING */ 
+
+/**************************************************************************
+  check for changes in global effects and send them to the clients 
+  if necessary.
+**************************************************************************/
+static void send_global_effect(struct player *pplayer, struct effect *eff,
+                               bool add_effect)
+{
+  struct packet_global_effect packet;
+
+  struct effect_defn *defn = &packet.effect_def[0];
+
+  defn->type = eff->defn->type;
+  defn->range = eff->defn->range;
+  defn->amount = eff->defn->amount;
+  defn->value1 = eff->defn->value1;
+  defn->value2 = eff->defn->value2;
+  defn->cond_nat = -1;
+  defn->cond_gov = game.government_count;
+  defn->cond_adv = A_NONE;
+  defn->cond_bldg = eff->defn->cond_bldg;
+  defn->cond_eff = EFT_LAST;
+  defn->aff_terr = eff->defn->aff_terr;
+  defn->aff_spec = eff->defn->aff_spec;
+  defn->aff_unit = eff->defn->aff_unit;
+
+  packet.add_effect = add_effect;
+  packet.player = eff->plr->player_no;
+
+  lsend_packet_global_effect(&pplayer->connections, &packet);
+
+  printf("sending %s (%s)\n", effect_type_name(eff->defn->type),
+        add_effect ? "adding" : "deleting");
+  fflush(stdout);              /* DEBUGGING */
+}
+
+/**************************************************************************
+  on game start and reconnnect, send all effects not owned by dest to dest.
+**************************************************************************/
+void send_global_effects(struct conn_list *dest)
+{
+  conn_list_iterate(*dest, pconn) {
+    effect_vector_iterate(game.effects, eff) {
+      if (eff->plr == pconn->player) {
+          continue; /* don't send effects that the player knows about */
+      }
+
+      /* make sure the client only has one copy of this one */
+      send_global_effect(pconn->player, eff, FALSE);
+      send_global_effect(pconn->player, eff, TRUE);
+    } effect_vector_iterate_end;
+  } conn_list_iterate_end;
+}
+
+/**************************************************************************
+ The server needs to do more on delete. 
+
+ We need to make sure that the client is informed of changes to the
+ global effects vector. 
+**************************************************************************/
+void delete_effects(enum effect_class class, struct player *pplayer, 
+                    struct city *pcity, struct unit *punit, int id)
+{
+  struct effect_vector temp;
+  struct conn_list dest;
+
+  conn_list_init(&dest);
+
+  /* put the current vector of global effects in a safe place. */
+  effect_vector_init(&temp);
+  effect_vector_copy(&temp, &game.effects);
+
+  delete_effects_common(class, pplayer, pcity, punit, id);
+  
+  /* check if any effects in temp are missing in game.effects */
+  effect_vector_iterate(temp, eff) {
+    effect_vector_iterate(game.effects, eff2) {
+      if (eff->defn == eff2->defn && eff->plr == eff2->plr &&
+          eff->home == eff2->home && eff->id == eff2->id) {
+        goto endloop;
+      }
+    } effect_vector_iterate_end;
+
+    /* we found an eff which isn't in game.effects any longer */
+    players_iterate(pplayer) {
+      if (eff->plr == pplayer) {
+          continue; /* don't send effects that the player knows about */
+      }
+
+      send_global_effect(pplayer, eff, FALSE);
+    } players_iterate_end;
+    
+    endloop:;
+  } effect_vector_iterate_end;
+
+  effects_update_all();
+
+  effect_vector_free(&temp);  
+  conn_list_unlink_all(&dest);
+}
+
+/**************************************************************************
+  check for changes in global effects and send them to the clients 
+  if necessary.
+**************************************************************************/
+void effects_update_all(void)
+{
+  struct conn_list dest;
+
+  conn_list_init(&dest);
+
+  effects_update_all_common();
+
+  effect_vector_iterate(game.effects, eff) {
+    if (eff->has.changed) {
+      players_iterate(pplayer) {
+        if (eff->plr == pplayer) {
+          continue; /* don't send effects that the player knows about */
+        }
+
+        send_global_effect(pplayer, eff, is_effect_emitting(eff, NULL));
+      } players_iterate_end;
+    }
+  } effect_vector_iterate_end;
+
+  conn_list_unlink_all(&dest);
+}
diff -Nur -Xcvs/diff_ignore snap-pre/server/gamehand.h 
snap-eff/server/gamehand.h
--- snap-pre/server/gamehand.h  2002-04-25 20:36:31.000000000 -0500
+++ snap-eff/server/gamehand.h  2004-03-05 20:44:46.000000000 -0600
@@ -23,5 +23,6 @@
 void send_start_turn_to_clients(void);
 
 int update_timeout(void);
+void send_global_effects(struct conn_list *dest);
 
 #endif  /* FC__GAMEHAND_H */
diff -Nur -Xcvs/diff_ignore snap-pre/server/maphand.c snap-eff/server/maphand.c
--- snap-pre/server/maphand.c   2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/maphand.c   2004-03-05 20:44:46.000000000 -0600
@@ -17,9 +17,11 @@
 
 #include <assert.h>
 
+#include "effects.h"
 #include "events.h"
 #include "fcintl.h"
 #include "game.h"
+#include "improvement.h"
 #include "log.h"
 #include "map.h"
 #include "mem.h"
@@ -1421,6 +1423,7 @@
       map_set_continent(x, y, ++map.num_continents);
 
       allot_island_improvs();
+      allot_island_effects();
     } else {
       /* set the tile to something adjacent to it */
       map_set_continent(x, y, con);
@@ -1452,6 +1455,8 @@
       assign_continent_numbers();
 
       allot_island_improvs();
+      allot_island_effects();
+      allot_island_effects();
 
       send_all_known_tiles(NULL);
     }
diff -Nur -Xcvs/diff_ignore snap-pre/server/plrhand.c snap-eff/server/plrhand.c
--- snap-pre/server/plrhand.c   2004-02-22 11:12:06.000000000 -0600
+++ snap-eff/server/plrhand.c   2004-03-07 20:12:51.441764507 -0600
@@ -320,7 +320,7 @@
     bonus_tech_hack = TRUE;
   }
 
-  set_invention(plr, tech_found, TECH_KNOWN);
+  set_invention(plr, tech_found, TECH_KNOWN, TRUE);
   update_research(plr);
   remove_obsolete_buildings(plr);
   if (tech_flag(tech_found,TF_RAILROAD)) {
@@ -636,9 +636,9 @@
   struct nation_type *nation = get_nation_by_plr(plr);
 
   tech_type_iterate(i) {
-    set_invention(plr, i, TECH_UNKNOWN);
+    set_invention(plr, i, TECH_UNKNOWN, FALSE);
   } tech_type_iterate_end;
-  set_invention(plr, A_NONE, TECH_KNOWN);
+  set_invention(plr, A_NONE, TECH_KNOWN, TRUE);
 
   plr->research.techs_researched = 1;
 
@@ -649,7 +649,7 @@
     if (game.rgame.global_init_techs[i] == A_LAST) {
       break;
     }
-    set_invention(plr, game.rgame.global_init_techs[i], TECH_KNOWN);
+    set_invention(plr, game.rgame.global_init_techs[i], TECH_KNOWN, TRUE);
   }
 
   /*
@@ -659,13 +659,13 @@
     if (nation->init_techs[i] == A_LAST) {
       break;
     }
-    set_invention(plr, nation->init_techs[i], TECH_KNOWN);
+    set_invention(plr, nation->init_techs[i], TECH_KNOWN, TRUE);
   }
 
   for (i = 0; i < tech; i++) {
     update_research(plr);
     choose_random_tech(plr); /* could be choose_goal_tech -- Syela */
-    set_invention(plr, plr->research.researching, TECH_KNOWN);
+    set_invention(plr, plr->research.researching, TECH_KNOWN, TRUE);
   }
 
   /* Mark the reachable techs */
@@ -843,7 +843,11 @@
     return;
   }
 
+  /* remove current government effects and add the new ones... */
+  delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, pplayer->government);
   pplayer->government = government;
+  add_government_effects(pplayer, TRUE);
+
   notify_player(pplayer, _("Game: %s now governs the %s as a %s."), 
                pplayer->name, 
                get_nation_name_plural(pplayer->nation),
@@ -881,7 +885,13 @@
   } else {
     pplayer->revolution = game.revolution_length;
   }
-  pplayer->government=game.government_when_anarchy;
+
+  /* remove current government effects and add the new ones... */
+  delete_effects(EFC_GOVERNMENT, pplayer, NULL, NULL, pplayer->government);
+
+  pplayer->government = game.government_when_anarchy;
+  add_government_effects(pplayer, TRUE);
+
   notify_player_ex(pplayer, -1, -1, E_REVOLT_START,
                   _("Game: The %s have incited a revolt!"),
                   get_nation_name_plural(pplayer->nation));
@@ -1711,6 +1721,7 @@
   Nation_Type_id *civilwar_nations = get_nation_civilwar(pplayer->nation);
 
   /* make a new player */
+  player_init(cplayer);
   server_player_init(cplayer, TRUE);
   ai_data_init(cplayer);
 
diff -Nur -Xcvs/diff_ignore snap-pre/server/ruleset.c snap-eff/server/ruleset.c
--- snap-pre/server/ruleset.c   2004-02-27 23:37:21.000000000 -0600
+++ snap-eff/server/ruleset.c   2004-03-05 20:55:02.000000000 -0600
@@ -22,9 +22,11 @@
 
 #include "capability.h"
 #include "city.h"
+#include "effects.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
+#include "improvement.h"
 #include "log.h"
 #include "map.h"
 #include "mem.h"
@@ -102,6 +104,10 @@
 static void send_ruleset_cities(struct conn_list *dest);
 static void send_ruleset_game(struct conn_list *dest);
 
+static void fill_effect_defs(struct section_file *file, char *sec, char *name, 
+                             struct effect_defn_vector *vec, int count, 
+                             enum effect_class class);
+
 /**************************************************************************
   datafilename() wrapper: tries to match in two ways.
   Returns NULL on failure, the (statically allocated) filename on success.
@@ -495,7 +501,7 @@
   char **sec;
   struct advance *a;
   int num_techs; /* number of techs in the ruleset (means without A_NONE)*/
-  int i;
+  int i, count;
   const char *filename = secfile_filename(file);
   
   (void) check_ruleset_capabilities(file, "+1.9", filename);
@@ -506,6 +512,7 @@
   advances[A_NONE].req[1] = A_NONE;
   advances[A_NONE].flags = 0;
   advances[A_NONE].root_req = A_LAST;
+  effect_defn_vector_init(&advances[A_NONE].effect_defs);
 
   a = &advances[A_FIRST];
   
@@ -560,6 +567,15 @@
        secfile_lookup_int_default(file, -1, "%s.%s", sec[i], "cost");
     a->num_reqs = 0;
     
+    /* do effect definitions */
+    for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+                                               sec[i], count); count++) {
+      /* nothing */
+    }
+
+    fill_effect_defs(file, sec[i], a->name, &a->effect_defs, count, 
+                     EFC_TECH);
+
     a++;
   }
 
@@ -672,7 +688,7 @@
 static void load_ruleset_units(struct section_file *file)
 {
   struct unit_type *u;
-  int i, j, ival, nval, vet_levels, vet_levels_default;
+  int i, j, ival, nval, count, vet_levels, vet_levels_default;
   char *sval, **slist, **sec;
   const char *filename = secfile_filename(file);
   char **vnlist, **def_vnlist;
@@ -891,6 +907,15 @@
     }
     u->fuel = secfile_lookup_int(file,"%s.fuel", sec[i]);
 
+    /* do effect definitions */
+    for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+                                               sec[i], count); count++) {
+      /* nothing */
+    }
+    
+    fill_effect_defs(file, sec[i], u->name, &u->effect_defs, count,
+                     EFC_UNIT);
+
     u->happy_cost  = secfile_lookup_int(file, "%s.uk_happy", sec[i]);
     u->shield_cost = secfile_lookup_int(file, "%s.uk_shield", sec[i]);
     u->food_cost   = secfile_lookup_int(file, "%s.uk_food", sec[i]);
@@ -960,6 +985,7 @@
   lookup_tech_list(file, "u_specials", "partisan_req",
                   game.rtech.partisan_req, filename);
 
+
   /* Some more consistency checking: */
   unit_type_iterate(i) {
     if (unit_type_exists(i)) {
@@ -1116,9 +1142,7 @@
 {
   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);
@@ -1225,164 +1249,14 @@
 
     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++) {
+    /* do effect definitions */
+    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;
-       }
-      } 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;
-       } else {
-         e->cond_gov = g->index;
-       }
-      } 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;
-      }
-
-      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;
-      }
-
-      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_LAST;
-       } 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_LAST;
-           problem = TRUE;
-         }
-       }
-      } 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;
-         }
-       }
-      } else {
-       e->aff_spec = S_ALL;
-      }
-
-      if (!problem) {
-       k++;
-      }
-    }
-    b->effect[k].type = EFT_LAST;
+    fill_effect_defs(file, sec[i], b->name, &b->effect_defs, count, 
+                     EFC_IMPROVEMENT);
 
     /* FIXME: remove when gen-impr obsoletes */
     b->variant = secfile_lookup_int_default(file, 0, "%s.variant", sec[i]);
@@ -1417,15 +1291,15 @@
                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)) {
+      effect_defn_vector_iterate(b->effect_defs, defn) {
+       if (!tech_exists(defn->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;
+                 b->name, advances[defn->cond_adv].name, filename);
+         defn->cond_adv = A_LAST;
        }
-      }
+      } effect_defn_vector_iterate_end;
     }
   } impr_type_iterate_end;
 
@@ -1912,6 +1786,20 @@
     ai_gov_tech_hints[j].tech = A_LAST;
   }
 
+  /* effect definitions */
+  government_iterate(g) {
+    int i = g->index;
+    int count;
+
+    for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+                                               sec[i], count); count++) {
+      /* nothing */
+    }
+
+    fill_effect_defs(file, sec[i], g->name, &g->effect_defs, count, 
+                     EFC_GOVERNMENT);
+  } government_iterate_end;
+
   free(sec);
   section_file_check_unused(file, filename);
   section_file_free(file);
@@ -2182,7 +2070,7 @@
   char *bad_leader, *g;
   struct nation_type *pl;
   struct government *gov;
-  int dim, val, i, j, k, nval;
+  int dim, val, i, j, k, nval, count;
   char temp_name[MAX_LEN_NAME];
   char **techs, **leaders, **sec, **civilwar_nations;
   const char *filename = secfile_filename(file);
@@ -2413,6 +2301,15 @@
 
     pl->city_names = load_city_name_list(file, sec[i], ".cities");
 
+    /* effect definitions */
+    for (count = 0; secfile_lookup_str_default(file, NULL, "%s.effect%d.type",
+                                               sec[i], count); count++) {
+      /* nothing */
+    }
+
+    fill_effect_defs(file, sec[i], pl->name, &pl->effect_defs, count, 
+                     EFC_NATION);
+
     /* class and legend */
 
     pl->class =
@@ -2707,6 +2604,9 @@
       packet.helptext[0] = '\0';
     }
 
+    effect_defn_vector_to_array(&u->effect_defs, packet.effect_defs,
+                               &packet.effect_defs_count);
+
     lsend_packet_ruleset_unit(dest, &packet);
   } unit_type_iterate_end;
 }
@@ -2738,6 +2638,9 @@
       packet.helptext[0] = '\0';
     }
 
+    effect_defn_vector_to_array(&a->effect_defs, packet.effect_defs,
+                               &packet.effect_defs_count);
+
     lsend_packet_ruleset_tech(dest, &packet);
   } tech_type_iterate_end;
 }
@@ -2748,10 +2651,10 @@
 **************************************************************************/
 static void send_ruleset_buildings(struct conn_list *dest)
 {
+
   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);
@@ -2786,11 +2689,8 @@
     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++;
-    }
+    effect_defn_vector_to_array(&b->effect_defs, packet.effect_defs,
+                               &packet.effect_defs_count);
 
     lsend_packet_ruleset_building(dest, &packet);
   } impr_type_iterate_end;
@@ -2941,6 +2841,9 @@
     } else {
       gov.helptext[0] = '\0';
     }
+
+    effect_defn_vector_to_array(&g->effect_defs, gov.effect_defs,
+                               &gov.effect_defs_count);
       
     lsend_packet_ruleset_government(dest, &gov);
     
@@ -2965,15 +2868,16 @@
 **************************************************************************/
 static void send_ruleset_nations(struct conn_list *dest)
 {
-  struct packet_ruleset_nation packet;
-  struct nation_type *n;
-  int i, k;
+  int k;
+
+  for (k = 0; k < game.nation_count; k++) {
+    struct nation_type *n = get_nation_by_idx(k);
+    struct packet_ruleset_nation packet;
+    int i;
 
-  assert(sizeof(packet.init_techs) == sizeof(n->init_techs));
-  assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
+    assert(sizeof(packet.init_techs) == sizeof(n->init_techs));
+    assert(ARRAY_SIZE(packet.init_techs) == ARRAY_SIZE(n->init_techs));
 
-  for( k=0; k<game.nation_count; k++) {
-    n = get_nation_by_idx(k);
     packet.id = k;
     sz_strlcpy(packet.name, n->name_orig);
     sz_strlcpy(packet.name_plural, n->name_plural_orig);
@@ -2989,6 +2893,9 @@
     sz_strlcpy(packet.class, n->class);
     sz_strlcpy(packet.legend, n->legend);
 
+    effect_defn_vector_to_array(&n->effect_defs, packet.effect_defs,
+                               &packet.effect_defs_count);
+
     lsend_packet_ruleset_nation(dest, &packet);
   }
 }
@@ -3119,3 +3026,191 @@
   lsend_packet_thaw_hint(dest);
   conn_list_do_unbuffer(dest);
 }
+
+/**************************************************************************
+  initialize an effect_defn_vector and fill it with all definitions in 
+  section 'sec'
+**************************************************************************/
+static void fill_effect_defs(struct section_file *file, char *sec, char *name, 
+                             struct effect_defn_vector *vec, int count,
+                             enum effect_class class)
+{
+  int j;
+  char *item;
+  const char *filename = secfile_filename(file);
+
+  /* initialize list */
+  effect_defn_vector_init(vec);
+  effect_defn_vector_reserve(vec, count); 
+
+  for (j = 0; j < count; j++) {
+    struct effect_defn *defn = effect_defn_vector_get(vec, j);
+
+    /* lookup type */
+    item = secfile_lookup_str(file, "%s.effect%d.type", sec, j);
+    defn->type = effect_type_from_str(item);
+    if (defn->type == EFT_LAST) {
+      freelog(LOG_ERROR,
+              "for %s effect[%d].type couldn't match type \"%s\" (%s)",
+              name, j, item, filename);
+    }
+
+    /* lookup range */
+    item = secfile_lookup_str_default(file, 
+                                      class == EFC_UNIT ? "Local": "None", 
+                                      "%s.effect%d.range", sec, j);
+    defn->range = effect_range_from_str(item);
+
+    if (defn->range == EFR_LAST) {
+      freelog(LOG_ERROR,
+              "for %s effect[%d].range couldn't match range \"%s\" (%s)",
+              name, j, item, filename);
+    }
+
+    /* nation, government and tech effects are homeless and must be Player
+     * or World ranged. */
+    if (class > EFC_IMPROVEMENT && defn->range < EFR_PLAYER) {
+      freelog(LOG_ERROR,
+              "for %s effect[%d].range: range \"%s\" is not allowed. "
+              "Setting to \"Player\" range. (%s)",
+              name, j, item, filename);
+      defn->range = EFR_PLAYER;
+    }
+
+    /* unit effects must be Local ranged */
+    if (class == EFC_UNIT && defn->range != EFR_LOCAL) {
+      freelog(LOG_ERROR,
+              "for %s effect[%d].range: range \"%s\" is not allowed. "
+              "Setting to \"Local\" range. (%s)",
+              name, j, item, filename);
+      defn->range = EFR_LOCAL;
+    }
+
+    /* lookup "outside" */
+    defn->outside = secfile_lookup_bool_default(file, 0, "%s.effect%d.outside",
+                                                sec, j);
+
+    /* lookup amount and auxillary amounts */
+    defn->amount = secfile_lookup_int_default(file, 0, "%s.effect%d.amount", 
+                                              sec, j);
+    defn->value1 = secfile_lookup_int_default(file, 0, "%s.effect%d.value1", 
+                                              sec, j);
+    defn->value2 = secfile_lookup_int_default(file, 0, "%s.effect%d.value2", 
+                                              sec, j);
+
+    /* lookup cond_bldg */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_bldg", 
+                                      sec, j);
+    if (*item != '\0') {
+      defn->cond_bldg = find_improvement_by_name(item);
+      if (defn->cond_bldg == B_LAST) {
+        freelog(LOG_ERROR, "for %s effect[%d].cond_bldg couldn't match "
+                "improvement \"%s\" (%s)", name, j, item, filename);
+      }
+    } else {
+      defn->cond_bldg = B_LAST;
+    }
+
+    /* lookup cond_nat */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_nat", sec, 
j);
+    if (*item != '\0') {
+      int n = find_nation_by_name(item);
+
+      if (n == -1) {
+        freelog(LOG_ERROR, "for %s effect[%d].cond_nat couldn't match "
+                "nation \"%s\" (%s)", name, j, item, filename);
+        defn->cond_nat = -1;
+      } else {
+        defn->cond_nat = n;
+      }
+    } else {
+      defn->cond_nat = -1;
+    }
+
+    /* lookup cond_gov */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", sec, 
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)", name, j, item, filename);
+        defn->cond_gov = game.government_count;
+      } else {
+        defn->cond_gov = g->index;
+      }
+    } else {
+      defn->cond_gov = game.government_count;
+    }
+
+    /* lookup cond_adv */
+    item = secfile_lookup_str_default(file, "None", "%s.effect%d.cond_adv",
+                                      sec, j);
+    if (*item != '\0') {
+      defn->cond_adv = find_tech_by_name(item);
+      if (defn->cond_adv == A_LAST) {
+        freelog(LOG_ERROR, "for %s effect[%d].cond_adv couldn't match "
+                "tech \"%s\" (%s)", name, j, item, filename);
+      }
+    } else {
+      defn->cond_adv = A_NONE;
+    }
+
+    /* lookup cond_eff */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_eff", sec, 
j);
+    if (*item != '\0') {
+      defn->cond_eff = effect_type_from_str(item);
+      if (defn->cond_eff == EFT_LAST) {
+        freelog(LOG_ERROR, "for %s effect[%d].cond_eff couldn't match "
+                "effect \"%s\" (%s)", name, j, item, filename);
+      }
+    } else {
+      defn->cond_eff = EFT_LAST;
+    }
+
+    /* lookup aff_unit */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_unit", sec, 
j);
+    if (*item != '\0') {
+      defn->aff_unit = unit_class_from_str(item);
+      if (defn->aff_unit == UCL_LAST) {
+        freelog(LOG_ERROR, "for %s effect[%d].aff_unit couldn't match "
+                "class \"%s\" (%s)", name, j, item, filename);
+      }
+    } else {
+      defn->aff_unit = UCL_LAST;
+    }
+
+    /* lookup aff_terr */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_terr", sec, 
j);
+    if (*item != '\0') {
+      if (0 == strcmp("None", item)) {
+        defn->aff_terr = T_LAST;
+      } else {
+        defn->aff_terr = get_terrain_by_name(item);
+        if (defn->aff_terr >= T_UNKNOWN) {
+          freelog(LOG_ERROR, "for %s effect[%d].aff_terr couldn't match "
+                  "terrain \"%s\" (%s)", name, j, item, filename);
+          defn->aff_terr = T_LAST;
+        }
+      }
+    } else {
+      defn->aff_terr = T_UNKNOWN;
+    }
+
+    /* lookup aff_spec */
+    item = secfile_lookup_str_default(file, "", "%s.effect%d.aff_spec", sec, 
j);
+    if (*item != '\0') {
+      if (0 == strcmp("None", item)) {
+        defn->aff_spec = S_NO_SPECIAL;
+      } else {
+        defn->aff_spec = get_special_by_name(item);
+        if (defn->aff_spec == S_NO_SPECIAL) {
+          freelog(LOG_ERROR, "for %s effect[%d].aff_spec couldn't match "
+                  "special \"%s\" (%s)", name, j, item, filename);
+        }
+      }
+    } else {
+      defn->aff_spec = S_ALL;
+    }
+  }
+}
diff -Nur -Xcvs/diff_ignore snap-pre/server/savegame.c 
snap-eff/server/savegame.c
--- snap-pre/server/savegame.c  2004-03-05 21:00:46.000000000 -0600
+++ snap-eff/server/savegame.c  2004-03-05 20:44:46.000000000 -0600
@@ -22,9 +22,12 @@
 
 #include "capability.h"
 #include "city.h"
+#include "effects.h"
 #include "fcintl.h"
 #include "game.h"
+#include "government.h"
 #include "idex.h"
+#include "improvement.h"
 #include "log.h"
 #include "map.h"
 #include "mem.h"
@@ -663,6 +666,12 @@
   /* Add techs from game and nation, but ignore game.tech. */
   init_tech(plr, 0);
 
+  /* FIXME: right now barbarians don't have effects */
+  if (!is_barbarian(plr)) {
+    /* add nation effects */
+    add_nation_effects(plr, FALSE);
+  }
+
   /* not all players have teams */
   if (section_file_lookup(file, "player%d.team", plrno)) {
     char tmp[MAX_LEN_NAME];
@@ -677,6 +686,10 @@
     plr->nation=game.nation_count-1;
   }
   plr->government=secfile_lookup_int(file, "player%d.government", plrno);
+
+  /* add government effects */
+  add_government_effects(plr, FALSE);
+
   plr->embassy=secfile_lookup_int(file, "player%d.embassy", plrno);
 
   p = secfile_lookup_str_default(file, NULL, "player%d.city_style_by_name",
@@ -773,9 +786,7 @@
                                                "player%d.can_space", plrno);
 
   tech_type_iterate(i) {
-    if (p[i] == '1') {
-      set_invention(plr, i, TECH_KNOWN);
-    }
+    set_invention(plr, i, (p[i]=='1') ? TECH_KNOWN : TECH_UNKNOWN, FALSE);
   } tech_type_iterate_end;
 
   update_research(plr);
@@ -1023,9 +1034,13 @@
     improvement_status_init(pcity->improvements,
                            ARRAY_SIZE(pcity->improvements));
 
+    /* Initialise city's list improvement effects. */
+    effect_vector_init(&pcity->effects);
+    effect_vector_init(&pcity->impr_effects);
+
     impr_type_iterate(x) {
       if (*p != '\0' && *p++=='1') {
-        city_add_improvement(pcity,x);
+        city_add_improvement(pcity, x, FALSE);
       }
     } impr_type_iterate_end;
 
@@ -1694,7 +1709,9 @@
     impr_type_iterate(id) {
       buf[id] = (pcity->improvements[id] != I_NONE) ? '1' : '0';
     } impr_type_iterate_end;
+
     buf[game.num_impr_types] = '\0';
+
     secfile_insert_str(file, buf, "player%d.c%d.improvements", plrno, i);
 
     worklist_save(file, "player%d.c%d", plrno, i, &pcity->worklist);
@@ -2255,6 +2272,10 @@
     /* This is done after continents are assigned, but before effects 
      * are added. */
     allot_island_improvs();
+    allot_island_effects();
+
+    /* lots of effects are going to get added real-soon-now */
+    effects_defer_update();
 
     for(i=0; i<game.nplayers; i++) {
       player_load(&game.players[i], i, file); 
@@ -2310,6 +2331,10 @@
        check_city(pcity);
       } city_list_iterate_end;
     } players_iterate_end;
+
+    /* update effects */
+    effects_undefer_update();
+    effects_update_all();
   } else {
     game.nplayers = 0;
   }
diff -Nur -Xcvs/diff_ignore snap-pre/server/srv_main.c 
snap-eff/server/srv_main.c
--- snap-pre/server/srv_main.c  2004-02-22 11:12:07.000000000 -0600
+++ snap-eff/server/srv_main.c  2004-03-05 20:44:46.000000000 -0600
@@ -295,6 +295,7 @@
   send_all_known_cities(dest);
   send_all_known_units(dest);
   send_player_turn_notifications(dest);
+  send_global_effects(dest);
 }
 
 /**************************************************************************
@@ -469,6 +470,47 @@
     send_player_cities(pplayer);
   } players_iterate_end;
 
+#ifdef DEBUG /* DEBUGGING FIXME: remove when commiting the effects patch */
+  players_iterate(pplayer) {
+    freelog(LOG_DEBUG, "%s:\n--------------------------------", pplayer->name);
+    city_list_iterate(pplayer->cities, pcity) {
+#if 0
+      freelog(LOG_DEBUG, " %s feels...", pcity->name);
+      city_effects_iterate(pcity, EFT_ALL, eff) {
+        freelog(LOG_DEBUG, "  c: %s i: %d r: %s n: %s",
+                (eff->home) ? eff->home->name : "(homeless)",
+                eff->id, effect_range_name(eff->defn->range),
+                effect_type_name(eff->defn->type));
+      } city_effects_iterate_end;
+#endif
+#if 0
+{                                                                           
+  int _iter;                                                               
+  struct effect *eff;                                                     
+  for (_iter = 0; _iter < effect_vector_size(&pcity->impr_effects); _iter++) { 
 
+    eff = effect_vector_get(&pcity->impr_effects, _iter);
+          freelog(LOG_DEBUG, "  c: %s i: %d r: %s n: %s",
+                  (eff->home) ? eff->home->name : "(homeless)",
+                  eff->id, effect_range_name(eff->defn->range),
+                  effect_type_name(eff->defn->type));
+  }
+}
+#endif
+#if 0
+      built_impr_iterate(pcity, id) {
+      freelog(LOG_DEBUG, " %d's local effects ...", id);
+        improvement_effects_iterate(pcity, id, EFT_ALL, eff) { 
+          printf("  c: %s i: %d r: %s n: %s",
+                  (eff->home) ? eff->home->name : "(homeless)",
+                  eff->id, effect_range_name(eff->defn->range),
+                  effect_type_name(eff->defn->type)); fflush(stdout);
+        } improvement_effects_iterate_end;
+      } built_impr_iterate_end;
+#endif
+    } city_list_iterate_end;
+  } players_iterate_end;
+#endif
+
   flush_packets();  /* to curb major city spam */
   conn_list_do_unbuffer(&game.game_connections);
 
@@ -1631,11 +1673,13 @@
   server_state = RUN_GAME_STATE;
   (void) send_server_info_to_metaserver(TRUE, FALSE);
 
+  effects_defer_update();
   if(game.is_new_game) {
     /* Before the player map is allocated (and initiailized)! */
     game.fogofwar_old = game.fogofwar;
 
     allot_island_improvs();
+    allot_island_effects();
 
     players_iterate(pplayer) {
       player_map_allocate(pplayer);
@@ -1652,6 +1696,15 @@
     }
   }
 
+  /* add nation and government effects; add immed. effects if new game */
+  players_iterate(pplayer) {
+    add_nation_effects(pplayer, game.is_new_game);
+    add_government_effects(pplayer, game.is_new_game);
+  } players_iterate_end;
+  effects_undefer_update();
+  freelog(LOG_VERBOSE, "%%%%%%%%: srv_main nat/gov effects"); /* 
DEBUGGING/REMOVE */
+  effects_update_all();
+
   /* Set up alliances based on team selections */
   if (game.is_new_game) {
    players_iterate(pplayer) {
diff -Nur -Xcvs/diff_ignore snap-eff/common/effects.c snap-imm/common/effects.c
--- snap-eff/common/effects.c   2004-03-07 12:03:32.000000000 -0600
+++ snap-imm/common/effects.c   2004-03-07 17:13:22.000000000 -0600
@@ -192,8 +192,6 @@
   switch (defn->type) {
   case EFT_GIVE_IMM_ADV:
   case EFT_IMPROVE_REP:
-  case EFT_REVEAL_CITIES: /* this could be a continuing effect, anyone? */
-  case EFT_REVEAL_MAP:
   case EFT_ENABLE_NUKE:   /* these two effects are only immediate in that */
   case EFT_ENABLE_SPACE:  /* they flip bits which stay around */
     return TRUE;
@@ -310,13 +308,13 @@
   }
 }
 
-/******************************************************************
+/*******************************************************************
  if pcity is non-NULL, global, player, and island ranges will return for 
    their effect in that city and city and local ranges will be check in that
    city only.
  if id is not B_LAST, then all of the above applies and only id's effects in
  the city are iterated through. If id is specified, pcity must also be.
-  
+
 *******************************************************************/
 void effect_iterator_init(struct effect_iter *iter, struct player *pplayer, 
                           struct city *pcity, struct unit *punit,
@@ -1168,7 +1166,7 @@
         && (!pcity || _eff->home == pcity)                                   \
         && (id == B_LAST || _eff->id == id)) {                               \
       freelog(LOG_DEBUG, "deleted effect p: %s, c: %s i: %d n: %s",          \
-              pplayer->name, (pcity) ? pcity->name : "(homeless)",           \
+              _eff->plr->name, (pcity) ? pcity->name : "(homeless)",         \
               id, effect_type_name(defn->type));                             \
       memcpy(_eff, effect_vector_get(&(eff_list), size - 1),                 \
              sizeof(struct effect));                                         \
diff -Nur -Xcvs/diff_ignore snap-eff/common/improvement.c 
snap-imm/common/improvement.c
--- snap-eff/common/improvement.c       2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/common/improvement.c       2004-03-07 17:13:22.000000000 -0600
@@ -365,20 +365,13 @@
   effect_defn_vector_iterate(impr->effect_defs, defn) {
     /* is this improvement considered a space part? */
     if (defn->type == EFT_SPACE_PART) {
-      bool space_enabled = FALSE;
-
       /* if spaceship is already launched, can't build it */
       if (p->spaceship.state >= SSHIP_LAUNCHED) {
         return FALSE;
       }
 
       /* we can't build it though unless we feel the "Enable_Space" effect */
-      player_effects_iterate(p, EFT_ENABLE_SPACE, eff) {
-        space_enabled = TRUE;
-        break;
-      } player_effects_iterate_end;
-  
-      if (!space_enabled) {
+      if (!p->can_space) {
         return FALSE;
       }
 
diff -Nur -Xcvs/diff_ignore snap-eff/common/unittype.c 
snap-imm/common/unittype.c
--- snap-eff/common/unittype.c  2004-02-27 23:37:21.000000000 -0600
+++ snap-imm/common/unittype.c  2004-03-07 17:13:22.000000000 -0600
@@ -444,8 +444,9 @@
 
   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) && !p->can_nuke) {
     return FALSE;
+  }
   if (unit_type_flag(id, F_FANATIC)
       && !government_has_flag(get_gov_pplayer(p), G_FANATIC_TROOPS))
     return FALSE;
diff -Nur -Xcvs/diff_ignore snap-eff/server/cityturn.c 
snap-imm/server/cityturn.c
--- snap-eff/server/cityturn.c  2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/cityturn.c  2004-03-07 17:21:08.000000000 -0600
@@ -36,6 +36,7 @@
 #include "unit.h"
 
 #include "citytools.h"
+#include "gamehand.h"
 #include "gamelog.h"
 #include "maphand.h"
 #include "plrhand.h"
@@ -956,6 +957,10 @@
       space_part = FALSE;
       city_add_improvement(pcity, pcity->currently_building, TRUE);
     }
+
+    /* deal with any immediate effects */
+    handle_immediate_effects();
+
     pcity->before_change_shields -=
        impr_build_shield_cost(pcity->currently_building);
     pcity->shield_stock -= impr_build_shield_cost(pcity->currently_building);
@@ -983,33 +988,6 @@
                     _("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);
-
-      do_free_cost(pplayer);
-      first = pplayer->research.researching;
-      found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE, 
-                     A_NONE);
-
-      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,
                       _("Game: The %s have started "
diff -Nur -Xcvs/diff_ignore snap-eff/server/gamehand.c 
snap-imm/server/gamehand.c
--- snap-eff/server/gamehand.c  2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/gamehand.c  2004-03-07 17:13:22.000000000 -0600
@@ -32,6 +32,8 @@
 
 #include "gamehand.h"
 
+static void handle_enable_nuke(void);
+static void handle_enable_space(void);
 
 /****************************************************************************
   Initialize the game.id variable to a random string of characters.
@@ -371,6 +373,98 @@
 #include <stdio.h> /* DEBUGGING */ 
 
 /**************************************************************************
+ searches for effects that enable players to build nuclear units.
+**************************************************************************/
+static void handle_enable_nuke(void)
+{
+  if (game.can_nuke) {
+    return;
+  }
+
+  /* if we find a global effect, enable_nuke and then delete
+   * all other effects that do this: they're redundant */
+  global_effects_iterate(EFT_ENABLE_NUKE, eff) {
+    game.can_nuke = TRUE;
+
+    delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+    players_iterate(pplayer) {
+      pplayer->can_nuke = TRUE;
+
+      player_effects_iterate(pplayer, EFT_ENABLE_NUKE, eff) {
+        delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+        break;
+      } player_effects_iterate_end;
+    } players_iterate_end;
+
+    return;
+  } global_effects_iterate_end;
+
+  /* look for player-only effects */
+  players_iterate(pplayer) {
+    player_effects_iterate(pplayer, EFT_ENABLE_NUKE, eff) {
+      pplayer->can_nuke = TRUE;
+      delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+      break;
+    } player_effects_iterate_end;
+  } players_iterate_end;
+}
+
+/**************************************************************************
+ searches for effects that enable players to build space parts.
+**************************************************************************/
+static void handle_enable_space(void)
+{
+  if (game.can_space) {
+    return;
+  }
+
+  /* if we find a global effect, enable_space and then delete
+   * all other effects that do this: they're redundant */
+  global_effects_iterate(EFT_ENABLE_SPACE, eff) {
+    game.can_space = TRUE;
+
+    delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+    players_iterate(pplayer) {
+      pplayer->can_space = TRUE;
+ 
+      player_effects_iterate(pplayer, EFT_ENABLE_SPACE, eff) {
+        delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+        break;
+      } player_effects_iterate_end;
+    } players_iterate_end;
+
+    return;
+  } global_effects_iterate_end;
+
+  /* look for player-only effects */
+  players_iterate(pplayer) {
+    player_effects_iterate(pplayer, EFT_ENABLE_SPACE, eff) {
+      pplayer->can_space = TRUE;
+      delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+      break;
+    } player_effects_iterate_end;
+  } players_iterate_end;
+}
+
+/**************************************************************************
+  Handle all the immediate effects. This must be done for everybody.
+  N.B. handle_reveal_cities() and handle_reveal_map() are done in 
+       srv_main.c:end_turn()
+**************************************************************************/
+void handle_immediate_effects(void)
+{
+    handle_immediate_advance(); /* is first cuz new techs may recurse */
+    handle_improve_reputation();
+    handle_enable_nuke();
+    handle_enable_space();
+
+    /* update effects */
+    effects_update_all();
+}
+
+/**************************************************************************
   check for changes in global effects and send them to the clients 
   if necessary.
 **************************************************************************/
@@ -488,6 +582,9 @@
         if (eff->plr == pplayer) {
           continue; /* don't send effects that the player knows about */
         }
+        if (is_immediate_effect(eff->defn)) {
+          continue; /* don't send immediate effects */
+        }
 
         send_global_effect(pplayer, eff, is_effect_emitting(eff, NULL));
       } players_iterate_end;
diff -Nur -Xcvs/diff_ignore snap-eff/server/gamehand.h 
snap-imm/server/gamehand.h
--- snap-eff/server/gamehand.h  2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/gamehand.h  2004-03-07 17:13:22.000000000 -0600
@@ -23,6 +23,9 @@
 void send_start_turn_to_clients(void);
 
 int update_timeout(void);
+
+void handle_immediate_effects(void);
+
 void send_global_effects(struct conn_list *dest);
 
 #endif  /* FC__GAMEHAND_H */
diff -Nur -Xcvs/diff_ignore snap-eff/server/maphand.c snap-imm/server/maphand.c
--- snap-eff/server/maphand.c   2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/maphand.c   2004-03-07 17:13:22.000000000 -0600
@@ -203,6 +203,51 @@
 }
 
 /**************************************************************************
+ This is an immediate effect in that it is done immediately after the effect
+ has been activated, but the effect is not deleted until the origin of the
+ effect has been destroyed.
+
+ Right now this is a Player or World ranged effect only.
+ TODO: It's certainly possible to make this an Island ranged effect.
+**************************************************************************/
+void handle_reveal_cities(void)
+{
+  players_iterate(pplayer) {
+    player_effects_iterate(pplayer, EFT_REVEAL_CITIES, eff) {
+      players_iterate(other_player) {
+        city_list_iterate(other_player->cities, pcity) {
+          show_area(pplayer, pcity->x, pcity->y, 0);
+        } city_list_iterate_end;
+      } players_iterate_end;
+
+      break; /* only need to do for the first such effect */
+    } player_effects_iterate_end;
+  } players_iterate_end;
+}
+
+/**************************************************************************
+ This is an immediate effect in that it is done immediately after the effect
+ has been activated, but the effect is not deleted until the origin of the
+ effect has been destroyed.
+
+ Right now this is a Player or World ranged effect only.
+**************************************************************************/
+void handle_reveal_map(void)
+{
+  players_iterate(pplayer) {
+    player_effects_iterate(pplayer, EFT_REVEAL_MAP, eff) {
+
+      /* 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);
+
+      break; /* only need to do this for the first such effect */
+    } player_effects_iterate_end;
+  } players_iterate_end;
+}
+
+/**************************************************************************
 Return TRUE iff the player me really gives shared vision to player them.
 **************************************************************************/
 static bool really_gives_vision(struct player *me, struct player *them)
diff -Nur -Xcvs/diff_ignore snap-eff/server/maphand.h snap-imm/server/maphand.h
--- snap-eff/server/maphand.h   2003-12-14 18:20:53.000000000 -0600
+++ snap-imm/server/maphand.h   2004-03-07 17:13:22.000000000 -0600
@@ -51,6 +51,10 @@
 
 void global_warming(int effect);
 void nuclear_winter(int effect);
+
+void handle_reveal_cities(void);
+void handle_reveal_map(void);
+
 void give_map_from_player_to_player(struct player *pfrom, struct player 
*pdest);
 void give_seamap_from_player_to_player(struct player *pfrom, struct player 
*pdest);
 void give_citymap_from_player_to_player(struct city *pcity,
diff -Nur -Xcvs/diff_ignore snap-eff/server/plrhand.c snap-imm/server/plrhand.c
--- snap-eff/server/plrhand.c   2004-03-07 20:12:51.441764507 -0600
+++ snap-imm/server/plrhand.c   2004-03-07 20:12:31.130640221 -0600
@@ -265,6 +265,102 @@
 }
 
 /**************************************************************************
+ Gain a new tech from the Give_Imm_Adv effect. We delete the effect 
+ afterwords.  Because new techs may activate more Give_Imm_Adv effects, 
+ we may need to do this several times.
+
+ Only Player and World ranged effects need apply.
+**************************************************************************/
+void handle_immediate_advance(void)
+{
+  bool new_tech;
+  int i;
+
+  do {
+    new_tech = FALSE;
+
+    effects_defer_update(); /* don't let found_new_tech() recurse */
+
+    /* must give all players the tech[s] before deleting the effect */
+    global_effects_iterate(EFT_GIVE_IMM_ADV, eff) {
+      new_tech = TRUE;
+
+      players_iterate(pplayer) {
+        for (i = 0; i <  eff->defn->amount; i++) {
+          if (!is_future_tech(pplayer->research.researching)) {
+            notify_embassies(pplayer, NULL,
+                             _("Game: The %s have discovered %s."),
+                             get_nation_name_plural(pplayer->nation),
+                             advances[pplayer->research.researching].name);
+    
+            gamelog(GAMELOG_TECH, _("%s discover %s"),
+                    get_nation_name_plural(pplayer->nation),
+                    advances[pplayer->research.researching].name);
+          } else {
+            notify_embassies(pplayer, NULL,
+                             _("Game: The %s have dicovered Future Tech. %d."),
+                             get_nation_name_plural(pplayer->nation),
+                             pplayer->future_tech);
+    
+            gamelog(GAMELOG_TECH, _("%s discover Future Tech %d"),
+                    get_nation_name_plural(pplayer->nation), 
+                    pplayer->future_tech);
+          }
+
+          do_free_cost(pplayer);
+          found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
+                         A_NONE);
+        }
+      } players_iterate_end;
+
+      delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+
+    } global_effects_iterate_end;
+
+    /* there should be no more global EFT_GIVE_IMM_ADV effects left */
+    players_iterate(pplayer) {
+      player_effects_iterate(pplayer, EFT_GIVE_IMM_ADV, eff) {
+        new_tech = TRUE;
+
+        for (i = 0; i <  eff->defn->amount; i++) {
+          if (!is_future_tech(pplayer->research.researching)) {
+            notify_embassies(pplayer, NULL,
+                             _("Game: The %s have discovered %s."),
+                             get_nation_name_plural(pplayer->nation),
+                             advances[pplayer->research.researching].name);
+
+            gamelog(GAMELOG_TECH, _("%s discover %s"),
+                    get_nation_name_plural(pplayer->nation),
+                    advances[pplayer->research.researching].name);
+          } else {
+            notify_embassies(pplayer, NULL,
+                             _("Game: The %s have dicovered Future Tech. %d."),
+                             get_nation_name_plural(pplayer->nation),
+                             pplayer->future_tech);
+
+            gamelog(GAMELOG_TECH, _("%s discover Future Tech %d"),
+                    get_nation_name_plural(pplayer->nation), 
+                    pplayer->future_tech);
+          }
+
+          do_free_cost(pplayer);
+          found_new_tech(pplayer, pplayer->research.researching, TRUE, TRUE,
+                         A_NONE);
+        }
+
+        delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+      } player_effects_iterate_end;
+    } players_iterate_end;
+
+    effects_undefer_update();
+
+    if (new_tech) {
+      effects_update_all();
+    }
+  } while (new_tech);
+}
+
+/**************************************************************************
   Player has a new technology (from somewhere). was_discovery is passed 
   on to upgrade_city_rails. Logging & notification is not done here as 
   it depends on how the tech came. If next_tech is other than A_NONE, this 
@@ -500,6 +596,9 @@
 
   /* do all the updates needed after finding new tech */
   found_new_tech(plr, plr->research.researching, TRUE, FALSE, A_NONE);
+
+  /* deal with any immediate effects */
+  handle_immediate_effects();
 }
 
 /**************************************************************************
@@ -866,6 +965,10 @@
   }
 
   check_player_government_rates(pplayer);
+
+  /* deal with any immediate effects */
+  handle_immediate_effects();
+
   global_city_refresh(pplayer);
   send_player_info(pplayer, pplayer);
 }
@@ -943,6 +1046,31 @@
 }
 
 /**************************************************************************
+  handles the Improve_Rep effect
+**************************************************************************/
+void handle_improve_reputation(void)
+{
+  /* must give all players the reputation boost before deleting the effect */
+  global_effects_iterate(EFT_IMPROVE_REP, eff) {
+    players_iterate(pplayer) {
+      pplayer->reputation = MIN(GAME_MAX_REPUTATION, 
+        pplayer->reputation + pplayer->reputation * eff->defn->amount/100);
+    } players_iterate_end;
+
+    delete_effect(NULL, NULL, NULL, B_LAST, eff->defn);
+  } global_effects_iterate_end
+
+  players_iterate(pplayer) {
+    player_effects_iterate(pplayer, EFT_IMPROVE_REP, eff) {  
+      pplayer->reputation = MIN(GAME_MAX_REPUTATION, 
+        pplayer->reputation + pplayer->reputation * eff->defn->amount/100);
+
+      delete_effect(pplayer, NULL, NULL, B_LAST, eff->defn);
+    } player_effects_iterate_end;
+  } players_iterate_end;
+}
+
+/**************************************************************************
   Handles a player cancelling a "pact" with another player.
 
   packet.id is id of player we want to cancel a pact with
@@ -1736,6 +1864,13 @@
   cplayer->revolution = 1;
   cplayer->capital = TRUE;
 
+  if (game.can_space || pplayer->can_space) {
+    cplayer->can_space = TRUE;
+  }
+  if (game.can_nuke || pplayer->can_nuke) {
+    cplayer->can_nuke = TRUE;
+  }
+
   /* This should probably be DS_NEUTRAL when AI knows about diplomacy,
    * but for now AI players are always at war.
    */
diff -Nur -Xcvs/diff_ignore snap-eff/server/plrhand.h snap-imm/server/plrhand.h
--- snap-eff/server/plrhand.h   2004-02-22 11:12:06.000000000 -0600
+++ snap-imm/server/plrhand.h   2004-03-07 17:16:15.000000000 -0600
@@ -36,6 +36,7 @@
 void update_revolution(struct player *pplayer);
 void great_library(struct player *pplayer);
 void check_player_government_rates(struct player *pplayer);
+void handle_improve_reputation(void);
 void make_contact(struct player *pplayer1, struct player *pplayer2, int x,
                  int y);
 void maybe_make_contact(int x, int y, struct player *pplayer);
@@ -62,6 +63,7 @@
 
 struct conn_list *player_reply_dest(struct player *pplayer);
 
+void handle_immediate_advance(void);
 void found_new_tech(struct player *plr, int tech_found, bool was_discovery,
                     bool saving_bulbs, int next_tech);
 void found_new_future_tech(struct player *pplayer);
diff -Nur -Xcvs/diff_ignore snap-eff/server/srv_main.c 
snap-imm/server/srv_main.c
--- snap-eff/server/srv_main.c  2004-03-05 20:44:46.000000000 -0600
+++ snap-imm/server/srv_main.c  2004-03-07 17:13:22.000000000 -0600
@@ -301,31 +301,6 @@
 /**************************************************************************
 ...
 **************************************************************************/
-static void do_apollo_program(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) {
-         show_area(pplayer, pcity->x, pcity->y, 0);
-       } city_list_iterate_end;
-      } players_iterate_end;
-    } else {
-      /* 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);
-    }
-  }
-}
-
-/**************************************************************************
-...
-**************************************************************************/
 static void marco_polo_make_contact(void)
 {
   struct city *pcity = find_city_wonder(B_MARCO);
@@ -569,7 +544,11 @@
                             &game.nuclearwinter, &game.coolinglevel,
                             nuclear_winter);
   update_diplomatics();
-  do_apollo_program();
+
+  /* these need to be done every turn */
+  handle_reveal_cities();
+  handle_reveal_map();
+
   marco_polo_make_contact();
   make_history_report();
   send_player_turn_notifications(NULL);
diff -Nur -Xcvs/diff_ignore snap-imm/common/city.c snap-city/common/city.c
--- snap-imm/common/city.c      2004-03-05 20:46:34.000000000 -0600
+++ snap-city/common/city.c     2004-03-07 17:25:21.158584707 -0600
@@ -36,6 +36,7 @@
 #include "speclist_c.h"
 
 /* start helper functions for generic_city_refresh */
+static void city_init_tile_modifiers(struct city *pcity);
 static int content_citizens(struct player *pplayer);
 static void set_tax_income(struct city *pcity);
 static void add_buildings_effect(struct city *pcity);
@@ -514,6 +515,117 @@
 }
 
 /**************************************************************************
+ initialize tile modifier structs
+**************************************************************************/
+static void city_init_tile_modifiers(struct city *pcity)
+{
+  struct tile_modifier *modptr;
+
+  city_map_iterate(x, y) {
+    modptr = &pcity->tile_bonus[x][y];
+    modptr->trade = modptr->shields = modptr->food = 0;
+
+    modptr = &pcity->tile_add[x][y];
+    modptr->trade = modptr->shields = modptr->food = 0;
+
+    modptr = &pcity->tile_pct[x][y];
+    modptr->trade = modptr->shields = modptr->food = 100;
+  } city_map_iterate_end;
+}
+
+/**************************************************************************
+ used by effects_update_all()
+**************************************************************************/
+void update_city_per_tile_modifiers(struct city *pcity)
+{
+  enum tile_special_type tile_spec[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  enum tile_terrain_type tile_terr[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
+  city_init_tile_modifiers(pcity);
+
+  city_effects_iterate(pcity, EFT_ALL, eff) {
+    switch(eff->defn->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) {
+        struct tile_type *type;
+        int map_x, map_y, is_real;
+
+        /* fill tile_spec and tile_terr with this tile */
+        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_NO_SPECIAL;
+          tile_terr[x][y] = T_UNKNOWN;
+        }
+
+        type = get_tile_type(tile_terr[x][y]);
+
+        /* FIXME: is there a better place for this to be?? -mck */
+        /* City centre counts as farmland if we have the necessary tech */
+        if (is_city_center(x, y)
+            && tile_terr[x][y] == type->irrigation_result
+            && terrain_control.may_irrigate
+            && player_knows_techs_with_flag(city_owner(pcity), TF_FARMLAND)) {
+          tile_spec[x][y] |= S_FARMLAND;
+        }
+
+        /* check .aff_spec and .aff_terr */
+        if ((contains_special(tile_spec[x][y], eff->defn->aff_spec) 
+             || eff->defn->aff_spec == S_NO_SPECIAL)
+            && (tile_terr[x][y] == eff->defn->aff_terr
+                || eff->defn->aff_terr == T_UNKNOWN)) {
+          int amount = eff->defn->amount;
+
+          switch(eff->defn->type) {
+          case EFT_TRADE_ADD_TILE:
+            pcity->tile_add[x][y].trade += amount;
+            break;
+          case EFT_TRADE_INC_TILE:
+            pcity->tile_bonus[x][y].trade += amount;
+            break;
+          case EFT_TRADE_PER_TILE:
+            pcity->tile_pct[x][y].trade *= amount / 100; 
+            break;
+          case EFT_PROD_ADD_TILE:
+            pcity->tile_add[x][y].shields += amount;
+            break;
+          case EFT_PROD_INC_TILE:
+            pcity->tile_bonus[x][y].shields += amount;
+            break;
+          case EFT_PROD_PER_TILE:
+            pcity->tile_pct[x][y].shields *= amount / 100;
+            break;
+          case EFT_FOOD_ADD_TILE:
+            pcity->tile_add[x][y].food += amount;
+            break;
+          case EFT_FOOD_INC_TILE:
+            pcity->tile_bonus[x][y].food += amount;
+            break;
+          case EFT_FOOD_PER_TILE:
+            pcity->tile_pct[x][y].food *= amount / 100;
+            break;
+          default:
+            break;
+          }
+        }
+      } city_map_iterate_end;
+    default:
+      break;
+    }
+  } city_effects_iterate_end;
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 int get_shields_tile(int x, int y)
@@ -580,11 +692,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 (is_ocean(tile_t) && city_got_building(pcity, B_OFFSHORE)) {
-    s++;
+
+  /* add tile modifiers from effects */
+  s += pcity->tile_bonus[x][y].shields;
+  if (s > 0) {
+    s += pcity->tile_add[x][y].shields;
   }
+  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);
@@ -674,6 +789,19 @@
   if (contains_special(spec_t, S_ROAD)) {
     t += (get_tile_type(tile_t))->road_trade_incr;
   }
+
+
+  /* add tile modifiers from effects */
+  t += pcity->tile_bonus[x][y].trade;
+  if (t > 0) {
+    t += pcity->tile_add[x][y].trade;
+  }
+  /* FIXME: are we sure? and if so, why not food and shields? -mck */
+  if (t < 0) {
+    t = 0;  /* Don't want tiles producing negative trade */
+  }
+  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);
@@ -686,11 +814,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--;
@@ -785,17 +908,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 (is_ocean(tile_t) && city_got_building(pcity, B_HARBOUR)) {
-    f++;
+  /* add tile modifiers from effects */
+  f += pcity->tile_bonus[x][y].food;
+  if (f > 0) {
+    f += pcity->tile_add[x][y].food;
   }
+  f *= pcity->tile_pct[x][y].food / 100;
 
   if (contains_special(spec_t, S_RAILROAD))
     f+=(f*terrain_control.rail_food_bonus)/100;
@@ -2608,6 +2728,8 @@
   pcity->tax_bonus = 100;
   pcity->science_bonus = 100;
 
+  city_init_tile_modifiers(pcity); 
+
   unit_list_init(&pcity->units_supported);
   pcity->debug = FALSE;
 
diff -Nur -Xcvs/diff_ignore snap-imm/common/city.h snap-city/common/city.h
--- snap-imm/common/city.h      2004-03-05 20:44:46.000000000 -0600
+++ snap-city/common/city.h     2004-03-07 17:25:21.160584238 -0600
@@ -207,6 +207,12 @@
                       * all units coming to kill us. */
 };
 
+struct tile_modifier {
+  int trade;
+  int shields;
+  int food;
+};
+
 struct city {
   int id;
   int owner;
@@ -237,6 +243,11 @@
   int trade_prod, corruption, tile_trade;
   int shield_bonus, tax_bonus, science_bonus; /* more CPU savings! */
 
+  /* per tile production bonuses from effects */
+  struct tile_modifier tile_bonus[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  struct tile_modifier tile_add[CITY_MAP_SIZE][CITY_MAP_SIZE];
+  struct tile_modifier tile_pct[CITY_MAP_SIZE][CITY_MAP_SIZE];
+
   /* the totals */
   int luxury_total, tax_total, science_total;
   
@@ -392,6 +403,8 @@
 bool city_map_to_map(int *map_x, int *map_y, const struct city *const pcity,
                    int city_map_x, int city_map_y);
 
+void update_city_per_tile_modifiers(struct city *pcity);
+
 /* shield on spot */
 int city_get_shields_tile(int x, int y, struct city *pcity);
 int base_city_get_shields_tile(int x, int y, struct city *pcity,
diff -Nur -Xcvs/diff_ignore snap-imm/common/effects.c snap-city/common/effects.c
--- snap-imm/common/effects.c   2004-03-07 17:13:22.000000000 -0600
+++ snap-city/common/effects.c  2004-03-07 17:25:21.162583770 -0600
@@ -487,6 +487,11 @@
       } city_list_iterate_end;
     } players_iterate_end;
   }
+
+  /* update per tile modifiers */
+  cities_iterate(pcity) {
+    update_city_per_tile_modifiers(pcity);
+  } cities_iterate_end;
 } 
 
 /*******************************************************************

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