Complete.Org: Mailing Lists: Archives: freeciv-dev: September 2005:
[Freeciv-Dev] Re: (PR#13878) redesign observers
Home

[Freeciv-Dev] Re: (PR#13878) redesign observers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#13878) redesign observers
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 6 Sep 2005 15:13:14 -0700
Reply-to: bugs@xxxxxxxxxxx

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

Here is an updated patch.

I audited every user of game.player_ptr in client/ and 
client/gui-gtk-2.0/.  Except for mistakes I made in this, everything 
should now work properly.

Observers are now substantially more powerful.  They can see city and 
unit internals of all players' units and cities.  They can open all city 
dialogs, etc.  This is basically needed for the new civ-editor model.

One additional cleanup would be to have more querying functions for 
observer mode.  We already have (for instance) can_client_change_view, 
can_client_issue_orders, can_player_see_city_internals, and 
can_player_see_units_in_city.  However none of these (except for 
can_client_issue_orders) is particularly useful for non-player 
observers.  We should have new functions can_client_view_player, 
can_conn_see_city_internals, can_conn_see_units_in_city, etc.

I also fixed some semi-related bugs and did cleanups not directly related.

- All sorts of tech and other common functions now work with a NULL 
player.  An obvious example is get_tech_name, which will now just return 
"Future Tech" if no player is given (normally it returns "Future Tech 5" 
or whatever).  A less obvious (but helpful) one is get_invention which 
will always return TECH_KNOWN for null-players.  In general I changed 
query functions to return useful values for NULL player even if these 
values weren't exactly correct.

- Many places in the client can simply avoid using game.player_ptr.  For 
instance when looking for a unit's homecity we don't need to use 
game.player_ptr, we can just use punit->owner.

- There's a bug in game_remove_player whereby the nation is cleared 
before everything else.  But log calls in the callers try to log the 
nation which can cause a crash.

-jason


Index: client/attribute.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/attribute.c,v
retrieving revision 1.21
diff -p -u -r1.21 attribute.c
--- client/attribute.c  8 Feb 2005 22:14:16 -0000       1.21
+++ client/attribute.c  6 Sep 2005 22:01:38 -0000
@@ -257,6 +257,10 @@ void attribute_flush(void)
 {
   struct player *pplayer = game.player_ptr;
 
+  if (!pplayer) {
+    return;
+  }
+
   assert(attribute_hash != NULL);
 
   if (hash_num_entries(attribute_hash) == 0)
@@ -280,6 +284,10 @@ void attribute_restore(void)
 {
   struct player *pplayer = game.player_ptr;
 
+  if (!pplayer) {
+    return;
+  }
+
   assert(attribute_hash != NULL);
 
   if (!unserialize_hash(attribute_hash, pplayer->attribute_block.data,
Index: client/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.85
diff -p -u -r1.85 citydlg_common.c
--- client/citydlg_common.c     1 Aug 2005 23:09:35 -0000       1.85
+++ client/citydlg_common.c     6 Sep 2005 22:01:39 -0000
@@ -318,7 +318,7 @@ void get_city_dialog_production_row(char
     }
     my_snprintf(buf[2], column_size, "%d", unit_build_shield_cost(ptype));
   } else {
-    struct player *pplayer = game.player_ptr;
+    struct player *pplayer = pcity->owner;
 
     /* Total & turns left meaningless on capitalization */
     if (building_has_effect(target.value, EFT_PROD_TO_GOLD)) {
Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.234
diff -p -u -r1.234 civclient.c
--- client/civclient.c  5 Sep 2005 15:55:45 -0000       1.234
+++ client/civclient.c  6 Sep 2005 22:01:39 -0000
@@ -724,8 +724,9 @@ bool can_client_issue_orders(void)
 **************************************************************************/
 bool can_meet_with_player(const struct player *pplayer)
 {
-  return (could_meet_with_player(game.player_ptr, pplayer)
-          && can_client_issue_orders());
+  return (can_client_issue_orders()
+         && game.player_ptr
+         && could_meet_with_player(game.player_ptr, pplayer));
 }
 
 /**************************************************************************
@@ -734,7 +735,9 @@ bool can_meet_with_player(const struct p
 **************************************************************************/
 bool can_intel_with_player(const struct player *pplayer)
 {
-  return could_intel_with_player(game.player_ptr, pplayer);
+  return (client_is_observer()
+         || (game.player_ptr
+             && could_intel_with_player(game.player_ptr, pplayer)));
 }
 
 /**************************************************************************
@@ -744,7 +747,7 @@ bool can_intel_with_player(const struct 
 **************************************************************************/
 bool can_client_change_view(void)
 {
-  return (game.player_ptr
+  return ((game.player_ptr || client_is_observer())
          && (get_client_state() == CLIENT_GAME_RUNNING_STATE
              || get_client_state() == CLIENT_GAME_OVER_STATE));
 }
Index: client/climap.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/climap.c,v
retrieving revision 1.10
diff -p -u -r1.10 climap.c
--- client/climap.c     5 May 2005 18:32:46 -0000       1.10
+++ client/climap.c     6 Sep 2005 22:01:39 -0000
@@ -19,9 +19,9 @@
 #include "map.h"
 #include "shared.h"
 
-#include "tilespec.h"           /* tileset_is_isometric(tileset) */
-
+#include "civclient.h"
 #include "climap.h"
+#include "tilespec.h"           /* tileset_is_isometric(tileset) */
 
 /************************************************************************
  A tile's "known" field is used by the server to store whether _each_
@@ -35,6 +35,9 @@
 *************************************************************************/
 enum known_type client_tile_get_known(const struct tile *ptile)
 {
+  if (!game.player_ptr && client_is_observer()) {
+    return TILE_KNOWN;
+  }
   return tile_get_known(ptile, game.player_ptr);
 }
 
Index: client/climisc.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/climisc.c,v
retrieving revision 1.180
diff -p -u -r1.180 climisc.c
--- client/climisc.c    4 Sep 2005 04:31:16 -0000       1.180
+++ client/climisc.c    6 Sep 2005 22:01:39 -0000
@@ -100,7 +100,8 @@ void client_remove_unit(struct unit *pun
 
   pcity = tile_get_city(ptile);
   if (pcity) {
-    if (can_player_see_units_in_city(game.player_ptr, pcity)) {
+    if (!game.player_ptr
+       || can_player_see_units_in_city(game.player_ptr, pcity)) {
       pcity->client.occupied =
        (unit_list_size(pcity->tile->units) > 0);
     }
@@ -111,12 +112,15 @@ void client_remove_unit(struct unit *pun
            TILE_XY(pcity->tile));
   }
 
-  pcity = player_find_city_by_id(game.player_ptr, hc);
-  if (pcity) {
-    refresh_city_dialog(pcity);
-    freelog(LOG_DEBUG, "home city %s, %s, (%d %d)", pcity->name,
-           get_nation_name(city_owner(pcity)->nation),
-           TILE_XY(pcity->tile));
+  /* FIXME: this can cause two refreshes to be done? */
+  if (game.player_ptr) {
+    pcity = player_find_city_by_id(game.player_ptr, hc);
+    if (pcity) {
+      refresh_city_dialog(pcity);
+      freelog(LOG_DEBUG, "home city %s, %s, (%d %d)", pcity->name,
+             get_nation_name(city_owner(pcity)->nation),
+             TILE_XY(pcity->tile));
+    }
   }
 
   refresh_unit_mapcanvas(&old_unit, ptile, TRUE, FALSE);
@@ -163,6 +167,10 @@ void client_change_all(struct city_produ
   char buf[512];
   int last_request_id = 0;
 
+  if (!can_client_issue_orders()) {
+    return;
+  }
+
   my_snprintf(buf, sizeof(buf),
              _("Changing production of every %s into %s."),
              from.is_unit ? get_unit_type(from.value)->name
@@ -193,7 +201,8 @@ void client_change_all(struct city_produ
 const char *get_embassy_status(const struct player *me,
                               const struct player *them)
 {
-  if (me == them
+  if (!me || !them
+      || me == them
       || !them->is_alive
       || !me->is_alive) {
     return "-";
@@ -220,13 +229,13 @@ const char *get_embassy_status(const str
 const char *get_vision_status(const struct player *me,
                              const struct player *them)
 {
-  if (gives_shared_vision(me, them)) {
+  if (me && them && gives_shared_vision(me, them)) {
     if (gives_shared_vision(them, me)) {
       return Q_("?vision:Both");
     } else {
       return Q_("?vision:To Them");
     }
-  } else if (gives_shared_vision(them, me)) {
+  } else if (me && them && gives_shared_vision(them, me)) {
     return Q_("?vision:To Us");
   } else {
     return "";
@@ -375,7 +384,8 @@ struct sprite *client_cooling_sprite(voi
 **************************************************************************/
 struct sprite *client_government_sprite(void)
 {
-  if (can_client_change_view() && game.control.government_count > 0) {
+  if (can_client_change_view() && game.player_ptr
+      && game.control.government_count > 0) {
     struct government *gov = game.player_ptr->government;
 
     return get_government_sprite(tileset, gov);
@@ -404,15 +414,15 @@ void center_on_something(void)
   can_slide = FALSE;
   if ((punit = get_unit_in_focus())) {
     center_tile_mapcanvas(punit->tile);
-  } else if ((pcity = find_palace(game.player_ptr))) {
+  } else if (game.player_ptr && (pcity = find_palace(game.player_ptr))) {
     /* Else focus on the capital. */
     center_tile_mapcanvas(pcity->tile);
-  } else if (city_list_size(game.player_ptr->cities) > 0) {
+  } else if (game.player_ptr && city_list_size(game.player_ptr->cities) > 0) {
     /* Just focus on any city. */
     pcity = city_list_get(game.player_ptr->cities, 0);
     assert(pcity != NULL);
     center_tile_mapcanvas(pcity->tile);
-  } else if (unit_list_size(game.player_ptr->units) > 0) {
+  } else if (game.player_ptr && unit_list_size(game.player_ptr->units) > 0) {
     /* Just focus on any unit. */
     punit = unit_list_get(game.player_ptr->units, 0);
     assert(punit != NULL);
@@ -635,7 +645,9 @@ void name_and_sort_items(struct city_pro
 }
 
 /**************************************************************************
-...
+  Return possible production targets for the current player's cities.
+
+  FIXME: this should probably take a pplayer argument.
 **************************************************************************/
 int collect_production_targets(struct city_production *targets,
                               struct city **selected_cities,
@@ -650,6 +662,10 @@ int collect_production_targets(struct ci
   cid cid;
   int items_used = 0;
 
+  if (!game.player_ptr) {
+    return 0;
+  }
+
   for (cid = first; cid < last; cid++) {
     bool append = FALSE;
     struct city_production target = cid_decode(cid);
@@ -683,6 +699,8 @@ int collect_production_targets(struct ci
 /**************************************************************************
  Collect the cids of all targets (improvements and units) which are
  currently built in a city.
+
+  FIXME: this should probably take a pplayer argument.
 **************************************************************************/
 int collect_currently_building_targets(struct city_production *targets)
 {
@@ -690,6 +708,10 @@ int collect_currently_building_targets(s
   int cids_used = 0;
   cid cid;
 
+  if (!game.player_ptr) {
+    return 0;
+  }
+
   memset(mapping, 0, sizeof(mapping));
   city_list_iterate(game.player_ptr->cities, pcity) {
     mapping[cid_encode_from_city(pcity)] = TRUE;
@@ -708,11 +730,17 @@ int collect_currently_building_targets(s
 /**************************************************************************
  Collect the cids of all targets (improvements and units) which can
  be build in a city.
+
+  FIXME: this should probably take a pplayer argument.
 **************************************************************************/
 int collect_buildable_targets(struct city_production *targets)
 {
   int cids_used = 0;
 
+  if (!game.player_ptr) {
+    return 0;
+  }
+
   impr_type_iterate(id) {
     if (can_player_build_improvement(game.player_ptr, id)) {
       targets[cids_used].is_unit = FALSE;
@@ -735,6 +763,8 @@ int collect_buildable_targets(struct cit
 /**************************************************************************
  Collect the cids of all targets which can be build by this city or
  in general.
+
+  FIXME: this should probably take a pplayer argument.
 **************************************************************************/
 int collect_eventually_buildable_targets(struct city_production *targets,
                                         struct city *pcity,
@@ -742,6 +772,10 @@ int collect_eventually_buildable_targets
 {
   int cids_used = 0;
 
+  if (!game.player_ptr) {
+    return 0;
+  }
+
   impr_type_iterate(id) {
     bool can_build = can_player_build_improvement(game.player_ptr, id);
     bool can_eventually_build =
@@ -811,7 +845,8 @@ int num_supported_units_in_city(struct c
 {
   struct unit_list *plist;
 
-  if (pcity->owner != game.player_ptr) {
+  if (game.player_ptr && pcity->owner != game.player_ptr) {
+    /* Other players don't see inside the city (but observers do). */
     plist = pcity->info_units_supported;
   } else {
     plist = pcity->units_supported;
@@ -827,7 +862,8 @@ int num_present_units_in_city(struct cit
 {
   struct unit_list *plist;
 
-  if (pcity->owner != game.player_ptr) {
+  if (game.player_ptr && pcity->owner != game.player_ptr) {
+    /* Other players don't see inside the city (but observers do). */
     plist = pcity->info_units_present;
   } else {
     plist = pcity->tile->units;
@@ -857,8 +893,8 @@ void handle_event(char *message, struct 
   if (BOOL_VAL(where & MW_MESSAGES)) {
     add_notify_window(message, ptile, event);
   }
-  if (BOOL_VAL(where & MW_POPUP) &&
-      (!game.player_ptr->ai.control)) {
+  if (BOOL_VAL(where & MW_POPUP)
+      && (!game.player_ptr || !game.player_ptr->ai.control)) {
     popup_notify_goto_dialog(_("Popup Request"), message, ptile);
   }
 
@@ -1004,7 +1040,7 @@ void cityrep_buy(struct city *pcity)
     return;
   }
 
-  if (game.player_ptr->economic.gold >= value) {
+  if (pcity->owner->economic.gold >= value) {
     city_buy_production(pcity);
   } else {
     char buf[512];
@@ -1018,7 +1054,7 @@ void cityrep_buy(struct city *pcity)
 
     my_snprintf(buf, sizeof(buf),
                _("%s costs %d gold and you only have %d gold."),
-               name, value, game.player_ptr->economic.gold);
+               name, value, pcity->owner->economic.gold);
     append_output_window(buf);
   }
 }
Index: client/control.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/control.c,v
retrieving revision 1.186
diff -p -u -r1.186 control.c
--- client/control.c    4 Sep 2005 01:15:48 -0000       1.186
+++ client/control.c    6 Sep 2005 22:01:40 -0000
@@ -145,10 +145,8 @@ void set_unit_focus(struct unit *punit)
 {
   struct unit *punit_old_focus = punit_focus;
 
-  if (punit && punit->owner != game.player_ptr) {
+  if (punit && game.player_ptr && punit->owner != game.player_ptr) {
     /* Callers should make sure this never happens. */
-    freelog(LOG_ERROR, "Trying to focus on another player's unit!");
-    assert(0);
     return;
   }
 
@@ -227,7 +225,7 @@ at the end of the goto, then they are st
 **************************************************************************/
 void update_unit_focus(void)
 {
-  if (!can_client_change_view()) {
+  if (!game.player_ptr || !can_client_change_view()) {
     return;
   }
   if (!punit_focus
@@ -261,7 +259,10 @@ void advance_unit_focus(void)
   struct unit *punit_old_focus = punit_focus;
   struct unit *candidate = find_best_focus_candidate(FALSE);
 
-  assert(can_client_change_view());
+  if (!game.player_ptr || !can_client_change_view()) {
+    set_unit_focus(NULL);
+    return;
+  }
 
   set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
   if (!can_client_change_view()) {
@@ -315,7 +316,8 @@ static struct unit *find_best_focus_cand
   int best_dist = 99999;
   struct tile *ptile;
 
-  if (!is_player_phase(game.player_ptr, game.info.phase)) {
+  if (!game.player_ptr
+      || !is_player_phase(game.player_ptr, game.info.phase)) {
     /* No focus unit wanted. */
     return NULL;
   }
@@ -457,7 +459,8 @@ double blink_turn_done_button(void)
   static struct timer *blink_timer = NULL;
   const double blink_time = 0.5; /* half-second blink interval */
 
-  if (game.player_ptr && game.player_ptr->is_alive
+  if (game.player_ptr
+      && game.player_ptr->is_alive
       && !game.player_ptr->phase_done) {
     if (!blink_timer || read_timer_seconds(blink_timer) > blink_time) {
       int is_waiting = 0, is_moving = 0;
@@ -588,13 +591,16 @@ void process_caravan_arrival(struct unit
     id = *p_id;
     free(p_id);
     p_id = NULL;
-    punit = player_find_unit_by_id(game.player_ptr, id);
+    punit = find_unit_by_id(id);
 
     if (punit && (unit_can_help_build_wonder_here(punit)
                  || unit_can_est_traderoute_here(punit))
-       && (!game.player_ptr->ai.control)) {
+       && (!game.player_ptr
+           || (game.player_ptr == punit->owner
+               && !game.player_ptr->ai.control))) {
       struct city *pcity_dest = tile_get_city(punit->tile);
       struct city *pcity_homecity = find_city_by_id(punit->homecity);
+
       if (pcity_dest && pcity_homecity) {
        popup_caravan_dialog(punit, pcity_homecity, pcity_dest);
        return;
@@ -793,7 +799,7 @@ void request_unit_unload_all(struct unit
        request_new_unit_activity(pcargo, ACTIVITY_IDLE);
       }
 
-      if (pcargo->owner == game.player_ptr) {
+      if (pcargo->owner == punit->owner) {
        plast = pcargo;
       }
     }
@@ -866,6 +872,9 @@ void request_diplomat_action(enum diplom
 
 void wakeup_sentried_units(struct tile *ptile)
 {
+  if (!can_client_issue_orders()) {
+    return;
+  }
   unit_list_iterate(ptile->units, punit) {
     if (punit->activity == ACTIVITY_SENTRY
        && game.player_ptr == punit->owner) {
@@ -1479,11 +1488,13 @@ void do_move_unit(struct unit *punit, st
    * into or out of a city.  For foreign cities this is handled separately,
    * via the occupied field of the short-city packet. */
   if (src_tile->city
-      && can_player_see_units_in_city(game.player_ptr, src_tile->city)) {
+      && (!game.player_ptr
+         || can_player_see_units_in_city(game.player_ptr, src_tile->city))) {
     update_city_description(src_tile->city);
   }
   if (dst_tile->city
-      && can_player_see_units_in_city(game.player_ptr, dst_tile->city)) {
+      && (!game.player_ptr
+         || can_player_see_units_in_city(game.player_ptr, dst_tile->city))) {
     update_city_description(dst_tile->city);
   }
 
@@ -1540,7 +1551,9 @@ void do_map_click(struct tile *ptile, en
     }
   }
   /* Otherwise use popups. */
-  else if (pcity && can_player_see_city_internals(game.player_ptr, pcity)) {
+  else if (pcity
+          && (!game.player_ptr
+              || can_player_see_city_internals(game.player_ptr, pcity))) {
     popup_city_dialog(pcity);
   }
   else if (unit_list_size(ptile->units) == 0 && !pcity
Index: client/goto.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.c,v
retrieving revision 1.91
diff -p -u -r1.91 goto.c
--- client/goto.c       20 Aug 2005 19:53:40 -0000      1.91
+++ client/goto.c       6 Sep 2005 22:01:40 -0000
@@ -1152,7 +1152,7 @@ struct pf_path *path_to_nearest_allied_c
   struct pf_map *map;
   struct pf_path *path = NULL;
 
-  if ((pcity = is_allied_city_tile(punit->tile, game.player_ptr))) {
+  if ((pcity = is_allied_city_tile(punit->tile, punit->owner))) {
     /* We're already on a city - don't go anywhere. */
     return NULL;
   }
@@ -1165,7 +1165,7 @@ struct pf_path *path_to_nearest_allied_c
 
     pf_next_get_position(map, &pos);
 
-    if ((pcity = is_allied_city_tile(pos.tile, game.player_ptr))) {
+    if ((pcity = is_allied_city_tile(pos.tile, punit->owner))) {
       break;
     }
   }
Index: client/mapctrl_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapctrl_common.c,v
retrieving revision 1.61
diff -p -u -r1.61 mapctrl_common.c
--- client/mapctrl_common.c     3 Aug 2005 16:19:07 -0000       1.61
+++ client/mapctrl_common.c     6 Sep 2005 22:01:40 -0000
@@ -325,6 +325,10 @@ void clipboard_copy_production(struct ti
   char msg[MAX_LEN_MSG];
   struct city *pcity = ptile->city;
 
+  if (!can_client_issue_orders()) {
+    return;
+  }
+
   if (pcity) {
     if (pcity->owner != game.player_ptr)  {
       return;
@@ -405,6 +409,9 @@ static void clipboard_send_production_pa
 **************************************************************************/
 void upgrade_canvas_clipboard(void)
 {
+  if (!can_client_issue_orders()) {
+    return;
+  }
   if (clipboard.is_unit)  {
     struct unit_type *u
       = can_upgrade_unittype(game.player_ptr, get_unit_type(clipboard.value));
@@ -592,7 +599,9 @@ void update_turn_done_button_state()
 
   if (turn_done_state) {
     if (waiting_for_end_turn
-       || (game.player_ptr->ai.control && !ai_manual_turn_done)) {
+       || (game.player_ptr
+           && game.player_ptr->ai.control
+           && !ai_manual_turn_done)) {
       send_turn_done();
     } else {
       update_turn_done_button(TRUE);
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.244
diff -p -u -r1.244 mapview_common.c
--- client/mapview_common.c     29 Aug 2005 13:56:49 -0000      1.244
+++ client/mapview_common.c     6 Sep 2005 22:01:41 -0000
@@ -1217,7 +1217,8 @@ static void show_full_citybar(struct can
   const struct citybar_sprites *citybar = get_citybar_sprites(tileset);
   const bool line1 = draw_city_names;
   const bool line2 = ((draw_city_productions || draw_city_growth)
-                     && pcity->owner == game.player_ptr);
+                     && (!game.player_ptr
+                         || pcity->owner == game.player_ptr));
   static char name[512], growth[32], prod[512], size[32];
   enum color_std growth_color;
   struct color *owner_color;
@@ -1253,7 +1254,8 @@ static void show_full_citybar(struct can
     get_text_size(&size_rect.w, &size_rect.h, FONT_CITY_SIZE, size);
     get_text_size(&name_rect.w, &name_rect.h, FONT_CITY_NAME, name);
 
-    if (can_player_see_units_in_city(game.player_ptr, pcity)) {
+    if (!game.player_ptr
+       || can_player_see_units_in_city(game.player_ptr, pcity)) {
       int count = unit_list_size(pcity->tile->units);
 
       count = CLIP(0, count, citybar->occupancy.size - 1);
@@ -1432,7 +1434,8 @@ static void show_small_citybar(struct ca
     *width = MAX(*width, total_width);
     *height += total_height + 3;
   }
-  if (draw_city_productions && pcity->owner == game.player_ptr) {
+  if (draw_city_productions
+      && (pcity->owner == game.player_ptr || !game.player_ptr)) {
     get_city_mapview_production(pcity, prod, sizeof(prod));
     get_text_size(&prod_rect.w, &prod_rect.h, FONT_CITY_PROD, prod);
 
@@ -1803,7 +1806,7 @@ struct city *find_city_or_settler_near_t
   }
 
   if (pcity) {
-    if (pcity->owner == game.player_ptr) {
+    if (!game.player_ptr || pcity->owner == game.player_ptr) {
       /* rule a */
       return pcity;
     } else {
@@ -1817,7 +1820,8 @@ struct city *find_city_or_settler_near_t
 
   city_map_checked_iterate(ptile, city_x, city_y, tile1) {
     pcity = tile_get_city(tile1);
-    if (pcity && pcity->owner == game.player_ptr
+    if (pcity
+       && (!game.player_ptr || pcity->owner == game.player_ptr)
        && get_worker_city(pcity, CITY_MAP_SIZE - 1 - city_x,
                           CITY_MAP_SIZE - 1 - city_y) == C_TILE_EMPTY) {
       /*
@@ -1847,7 +1851,7 @@ struct city *find_city_or_settler_near_t
 
     if (tile1) {
       unit_list_iterate(tile1->units, psettler) {
-       if (psettler->owner == game.player_ptr
+       if ((!game.player_ptr || psettler->owner == game.player_ptr)
            && unit_flag(psettler, F_CITIES)
            && city_can_be_built_here(psettler->tile, psettler)) {
          if (!closest_settler) {
@@ -2109,7 +2113,7 @@ void get_city_mapview_name_and_growth(st
 {
   my_snprintf(name_buffer, name_buffer_len, pcity->name);
 
-  if (pcity->owner == game.player_ptr) {
+  if (!game.player_ptr || pcity->owner == game.player_ptr) {
     int turns = city_turns_to_grow(pcity);
 
     if (turns == 0) {
Index: client/messagewin_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/messagewin_common.c,v
retrieving revision 1.24
diff -p -u -r1.24 messagewin_common.c
--- client/messagewin_common.c  25 Aug 2005 20:36:12 -0000      1.24
+++ client/messagewin_common.c  6 Sep 2005 22:01:41 -0000
@@ -75,8 +75,10 @@ void update_meswin_dialog(void)
     return;
   }
 
-  if (!is_meswin_open() && messages_total > 0 &&
-      (!game.player_ptr->ai.control)) {
+  if (!is_meswin_open() && messages_total > 0
+      && !client_is_observer()
+      && game.player_ptr
+      && !game.player_ptr->ai.control) {
     popup_meswin_dialog(FALSE);
     change = FALSE;
     return;
@@ -144,7 +146,9 @@ void add_notify_window(char *message, st
     if (messages[i].location_ok) {
       struct city *pcity = tile_get_city(messages[i].tile);
 
-      messages[i].city_ok = (pcity && city_owner(pcity) == game.player_ptr);
+      messages[i].city_ok = (pcity
+                            && (!game.player_ptr
+                                || city_owner(pcity) == game.player_ptr));
     } else {
       messages[i].city_ok = FALSE;
     }
@@ -193,7 +197,8 @@ void meswin_popup_city(int message_index
       center_tile_mapcanvas(ptile);
     }
 
-    if (pcity && city_owner(pcity) == game.player_ptr) {
+    if (pcity
+       && (!game.player_ptr || city_owner(pcity) == game.player_ptr)) {
       /* If the event was the city being destroyed, pcity will be NULL
        * and we'd better not try to pop it up.  It's also possible that
        * events will happen on enemy cities; we generally don't want to pop
Index: client/overview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/overview_common.c,v
retrieving revision 1.18
diff -p -u -r1.18 overview_common.c
--- client/overview_common.c    31 Aug 2005 20:18:52 -0000      1.18
+++ client/overview_common.c    6 Sep 2005 22:01:41 -0000
@@ -112,7 +112,7 @@ static struct color *overview_tile_color
     struct city *pcity = tile_get_city(ptile);
 
     if (pcity) {
-      if (pcity->owner == game.player_ptr) {
+      if (!game.player_ptr || pcity->owner == game.player_ptr) {
        return get_color(tileset, COLOR_OVERVIEW_MY_CITY);
       } else if (pplayers_allied(city_owner(pcity), game.player_ptr)) {
        /* Includes teams. */
@@ -126,7 +126,7 @@ static struct color *overview_tile_color
     struct unit *punit = find_visible_unit(ptile);
 
     if (punit) {
-      if (punit->owner == game.player_ptr) {
+      if (!game.player_ptr || punit->owner == game.player_ptr) {
        return get_color(tileset, COLOR_OVERVIEW_MY_UNIT);
       } else if (pplayers_allied(unit_owner(punit), game.player_ptr)) {
        /* Includes teams. */
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.548
diff -p -u -r1.548 packhand.c
--- client/packhand.c   5 Sep 2005 15:55:45 -0000       1.548
+++ client/packhand.c   6 Sep 2005 22:01:42 -0000
@@ -516,7 +516,8 @@ void handle_city_info(struct packet_city
    * investigating an enemy city we can't.  In that case we don't update
    * the occupied flag at all: it's already been set earlier and we'll
    * get an update if it changes. */
-  if (can_player_see_units_in_city(game.player_ptr, pcity)) {
+  if (!game.player_ptr
+      || can_player_see_units_in_city(game.player_ptr, pcity)) {
     pcity->client.occupied
       = (unit_list_size(pcity->tile->units) > 0);
   }
@@ -596,15 +597,17 @@ static void handle_city_packet_common(st
   }
 
   if (popup
-      && (!game.player_ptr->ai.control)
-      && can_client_issue_orders()) {
+      && can_client_issue_orders()
+      && game.player_ptr
+      && !game.player_ptr->ai.control) {
     update_menus();
     if (!city_dialog_is_open(pcity)) {
       popup_city_dialog(pcity);
     }
   }
 
-  if (!is_new && (pcity->owner==game.player_ptr || popup)) {
+  if (!is_new
+      && (!game.player_ptr || pcity->owner == game.player_ptr || popup)) {
     refresh_city_dialog(pcity);
   }
 
@@ -770,14 +773,16 @@ void handle_new_year(int year, int turn)
 #if 0
   /* This information shouldn't be needed, but if it is this is the only
    * way we can get it. */
-  turn_gold_difference=game.player_ptr->economic.gold-last_turn_gold_amount;
-  last_turn_gold_amount=game.player_ptr->economic.gold;
+  if (game.player_ptr) {
+    turn_gold_difference
+      = game.player_ptr->economic.gold - last_turn_gold_amount;
+    last_turn_gold_amount = game.player_ptr->economic.gold;
+  }
 #endif
 
   update_city_descriptions();
 
-  if (sound_bell_at_new_turn &&
-      (!game.player_ptr->ai.control || ai_manual_turn_done)) {
+  if (sound_bell_at_new_turn) {
     create_event(NULL, E_TURN_BELL, _("Start of turn %d"), game.info.turn);
   }
 
@@ -908,11 +913,6 @@ void handle_unit_info(struct packet_unit
 {
   struct unit *punit;
 
-  if (packet->owner != game.info.player_idx) {
-    freelog(LOG_ERROR, "Got packet_unit_info for unit of %s.",
-            game.players[packet->owner].name);
-  }
-
   punit = unpackage_unit(packet);
   if (handle_unit_packet_common(punit)) {
     free(punit);
@@ -997,6 +997,7 @@ static bool handle_unit_packet_common(st
 
       /* Wakeup Focus */
       if (wakeup_focus 
+         && game.player_ptr
           && !game.player_ptr->ai.control
           && punit->owner == game.player_ptr
           && punit->activity == ACTIVITY_SENTRY
@@ -1041,7 +1042,7 @@ static bool handle_unit_packet_common(st
       punit->orders.list = packet_unit->orders.list;
       packet_unit->orders.list = NULL;
 
-      if (punit->owner == game.player_ptr) {
+      if (!game.player_ptr || punit->owner == game.player_ptr) {
         refresh_unit_city_dialogs(punit);
       }
     } /*** End of Change in activity or activity's target. ***/
@@ -1112,7 +1113,8 @@ static bool handle_unit_packet_common(st
       }
 
       if(pcity)  {
-       if (can_player_see_units_in_city(game.player_ptr, pcity)) {
+       if (!game.player_ptr
+           || can_player_see_units_in_city(game.player_ptr, pcity)) {
          /* Unit moved out of a city - update the occupied status. */
          bool new_occupied =
            (unit_list_size(pcity->tile->units) > 0);
@@ -1131,7 +1133,8 @@ static bool handle_unit_packet_common(st
       }
       
       if((pcity=tile_get_city(punit->tile)))  {
-       if (can_player_see_units_in_city(game.player_ptr, pcity)) {
+       if (!game.player_ptr
+           || can_player_see_units_in_city(game.player_ptr, pcity)) {
          /* Unit moved into a city - obviously it's occupied. */
          if (!pcity->client.occupied) {
            pcity->client.occupied = TRUE;
@@ -1145,7 +1148,8 @@ static bool handle_unit_packet_common(st
          refresh_city_dialog(pcity);
        
         if((unit_flag(punit, F_TRADE_ROUTE) || unit_flag(punit, F_HELP_WONDER))
-          && (!game.player_ptr->ai.control)
+          && game.player_ptr
+          && !game.player_ptr->ai.control
           && punit->owner == game.player_ptr
           && !unit_has_orders(punit)
           && can_client_issue_orders()
@@ -1234,6 +1238,7 @@ static bool handle_unit_packet_common(st
   }
 
   if ((check_focus || get_unit_in_focus() == NULL)
+      && game.player_ptr
       && !game.player_ptr->ai.control
       && is_player_phase(game.player_ptr, game.info.phase)) {
     update_unit_focus();
@@ -1318,6 +1323,10 @@ void handle_unit_short_info(struct packe
 ****************************************************************************/
 void handle_map_info(int xsize, int ysize, int topology_id)
 {
+  if (!map_is_empty()) {
+    map_free();
+  }
+
   map.xsize = xsize;
   map.ysize = ysize;
   map.topology_id = topology_id;
@@ -1394,8 +1403,9 @@ static bool read_player_info_techs(struc
 **************************************************************************/
 void set_government_choice(struct government *government)
 {
-  if (government != game.player_ptr->government
-      && can_client_issue_orders()) {
+  if (can_client_issue_orders()
+      && game.player_ptr
+      && government != game.player_ptr->government) {
     dsend_packet_player_change_government(&aconnection, government->index);
   }
 }
@@ -1424,7 +1434,6 @@ void handle_player_info(struct packet_pl
 
   sz_strlcpy(pplayer->name, pinfo->name);
 
-  pplayer->is_observer = pinfo->is_observer;
   is_new_nation = player_set_nation(pplayer, get_nation_by_idx(pinfo->nation));
   pplayer->is_male=pinfo->is_male;
   team_add_player(pplayer, team_get_by_id(pinfo->team));
@@ -1501,7 +1510,7 @@ void handle_player_info(struct packet_pl
       science_dialog_update();
     }
     if (poptechup) {
-      if (!game.player_ptr->ai.control) {
+      if (game.player_ptr && !game.player_ptr->ai.control) {
        popup_science_dialog(FALSE);
       }
     }
@@ -1906,21 +1915,23 @@ void handle_tile_info(struct packet_tile
   if (old_known != packet->known) {
     known_changed = TRUE;
   }
-  BV_CLR(ptile->tile_known, game.info.player_idx);
-  BV_CLR(ptile->tile_seen, game.info.player_idx);
-  switch (packet->known) {
-  case TILE_KNOWN:
-    BV_SET(ptile->tile_known, game.info.player_idx);
-    BV_SET(ptile->tile_seen, game.info.player_idx);
-    break;
-  case TILE_KNOWN_FOGGED:
-    BV_SET(ptile->tile_known, game.info.player_idx);
-    break;
-  case TILE_UNKNOWN:
-    break;
-  default:
-    freelog(LOG_NORMAL, "Unknown tile value %d.", packet->known);
-    break;
+  if (game.player_ptr) {
+    BV_CLR(ptile->tile_known, game.info.player_idx);
+    BV_CLR(ptile->tile_seen, game.info.player_idx);
+    switch (packet->known) {
+    case TILE_KNOWN:
+      BV_SET(ptile->tile_known, game.info.player_idx);
+      BV_SET(ptile->tile_seen, game.info.player_idx);
+      break;
+    case TILE_KNOWN_FOGGED:
+      BV_SET(ptile->tile_known, game.info.player_idx);
+      break;
+    case TILE_UNKNOWN:
+      break;
+    default:
+      freelog(LOG_NORMAL, "Unknown tile value %d.", packet->known);
+      break;
+    }
   }
 
   if (packet->spec_sprite[0] != '\0') {
@@ -2358,7 +2369,6 @@ void handle_ruleset_nation(struct packet
   pl->city_style = p->city_style;
 
   pl->is_playable = p->is_playable;
-  pl->is_observer = p->is_observer;
   pl->is_barbarian = p->is_barbarian;
 
   memcpy(pl->init_techs, p->init_techs, sizeof(pl->init_techs));
@@ -2470,7 +2480,7 @@ void handle_unit_bribe_info(int unit_id,
 
   if (punit) {
     punit->bribe_cost = cost;
-    if (!game.player_ptr->ai.control) {
+    if (game.player_ptr && !game.player_ptr->ai.control) {
       popup_bribe_dialog(punit);
     }
   }
@@ -2485,7 +2495,7 @@ void handle_city_incite_info(int city_id
 
   if (pcity) {
     pcity->incite_revolt_cost = cost;
-    if (!game.player_ptr->ai.control) {
+    if (game.player_ptr && !game.player_ptr->ai.control) {
       popup_incite_dialog(pcity);
     }
   }
@@ -2519,7 +2529,7 @@ void handle_unit_diplomat_popup_dialog(i
   struct unit *pdiplomat =
       player_find_unit_by_id(game.player_ptr, diplomat_id);
 
-  if (pdiplomat) {
+  if (pdiplomat && can_client_issue_orders()) {
     process_diplomat_arrival(pdiplomat, target_id);
   }
 }
@@ -2533,7 +2543,7 @@ void handle_city_sabotage_list(int diplo
   struct unit *punit = player_find_unit_by_id(game.player_ptr, diplomat_id);
   struct city *pcity = find_city_by_id(city_id);
 
-  if (punit && pcity) {
+  if (punit && pcity && can_client_issue_orders()) {
     impr_type_iterate(i) {
       pcity->improvements[i] = BV_ISSET(improvements, i) ? I_ACTIVE : I_NONE;
     } impr_type_iterate_end;
@@ -2555,6 +2565,9 @@ void handle_endgame_report(struct packet
 **************************************************************************/
 void handle_player_attribute_chunk(struct packet_player_attribute_chunk 
*packet)
 {
+  if (!game.player_ptr) {
+    return;
+  }
   generic_handle_player_attribute_chunk(game.player_ptr, packet);
 
   if (packet->offset + packet->chunk_length == packet->total_length) {
Index: client/plrdlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/plrdlg_common.c,v
retrieving revision 1.23
diff -p -u -r1.23 plrdlg_common.c
--- client/plrdlg_common.c      18 Aug 2005 06:53:29 -0000      1.23
+++ client/plrdlg_common.c      6 Sep 2005 22:01:42 -0000
@@ -126,7 +126,7 @@ static const char *col_diplstate(const s
   static char buf[100];
   const struct player_diplstate *pds;
 
-  if (player == game.player_ptr) {
+  if (!game.player_ptr || player == game.player_ptr) {
     return "-";
   } else {
     pds = pplayer_get_diplstate(game.player_ptr, player);
@@ -145,7 +145,7 @@ static const char *col_diplstate(const s
 *******************************************************************/
 static const char *col_love(const struct player *player)
 {
-  if (player == game.player_ptr || !player->ai.control) {
+  if (!game.player_ptr || player == game.player_ptr || !player->ai.control) {
     return "-";
   } else {
     return love_text(player->ai.love[game.player_ptr->player_no]);
@@ -159,6 +159,11 @@ static int cmp_love(const struct player 
                           const struct player *player2)
 {
   int love1, love2;
+
+  if (!game.player_ptr) {
+    return player1->player_no - player2->player_no;
+  }
+
   if (player1 == game.player_ptr || !player1->ai.control) {
     love1 = MAX_AI_LOVE + 999;
   } else {
Index: client/repodlgs_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/repodlgs_common.c,v
retrieving revision 1.29
diff -p -u -r1.29 repodlgs_common.c
--- client/repodlgs_common.c    18 Aug 2005 06:44:27 -0000      1.29
+++ client/repodlgs_common.c    6 Sep 2005 22:01:42 -0000
@@ -47,6 +47,10 @@ void get_economy_report_data(struct impr
   *num_entries_used = 0;
   *total_cost = 0;
 
+  if (!game.player_ptr) {
+    return;
+  }
+
   impr_type_iterate(impr_id) {
     if (is_improvement(impr_id)) {
       int count = 0, cost = 0;
@@ -96,6 +100,13 @@ void get_economy_report_units_data(struc
 {
   int count, cost, partial_cost;
 
+  *num_entries_used = 0;
+  *total_cost = 0;
+
+  if (!game.player_ptr) {
+    return;
+  }
+
   unit_type_iterate(unittype) {
     cost = utype_upkeep_cost(unittype, game.player_ptr,
                              get_gov_pplayer(game.player_ptr), O_GOLD);
Index: client/reqtree.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/reqtree.c,v
retrieving revision 1.10
diff -p -u -r1.10 reqtree.c
--- client/reqtree.c    3 Sep 2005 10:07:18 -0000       1.10
+++ client/reqtree.c    6 Sep 2005 22:01:42 -0000
@@ -795,6 +795,11 @@ static enum color_std node_color(struct 
 {
   if (!node->is_dummy) {
     struct player_research* research = get_player_research(game.player_ptr);
+
+    if (!game.player_ptr || !research) {
+      return COLOR_REQTREE_KNOWN;
+    }
+
     if (research->researching == node->tech) {
       return COLOR_REQTREE_RESEARCHING;
     }
Index: client/text.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/text.c,v
retrieving revision 1.50
diff -p -u -r1.50 text.c
--- client/text.c       25 Aug 2005 20:36:12 -0000      1.50
+++ client/text.c       6 Sep 2005 22:01:42 -0000
@@ -84,11 +84,16 @@ const char *popup_info_text(struct tile 
   }
   if (game.info.borders > 0 && !pcity) {
     struct player *owner = tile_get_owner(ptile);
-    struct player_diplstate *ds = game.player_ptr->diplstates;
 
-    if (owner == game.player_ptr){
+    if (game.player_ptr && owner == game.player_ptr){
       astr_add_line(&str, _("Our Territory"));
+    } else if (owner && !game.player_ptr) {
+      /* TRANS: "Territory of the Polish" */
+      astr_add_line(&str, _("Territory of the %s"),
+                   get_nation_name_plural(owner->nation));
     } else if (owner) {
+      struct player_diplstate *ds = game.player_ptr->diplstates;
+
       if (ds[owner->player_no].type == DS_CEASEFIRE) {
        int turns = ds[owner->player_no].turns_left;
 
@@ -114,14 +119,19 @@ const char *popup_info_text(struct tile 
     /* Look at city owner, not tile owner (the two should be the same, if
      * borders are in use). */
     struct player *owner = city_owner(pcity);
-    struct player_diplstate *ds = game.player_ptr->diplstates;
     struct unit *apunit;
 
-    if (owner == game.player_ptr){
+    if (game.player_ptr && owner == game.player_ptr){
       /* TRANS: "City: Warsaw (Polish)" */
       astr_add_line(&str, _("City: %s (%s)"), pcity->name,
                    get_nation_name(owner->nation));
-    } else if (owner) {
+    } else if (!game.player_ptr) {
+      /* TRANS: "City: Warsaw (Polish)" */
+      astr_add_line(&str, _("City: %s (%s)"),
+                   pcity->name, get_nation_name(owner->nation));
+    } else {
+      struct player_diplstate *ds = game.player_ptr->diplstates;
+
       if (ds[owner->player_no].type == DS_CEASEFIRE) {
        int turns = ds[owner->player_no].turns_left;
 
@@ -167,14 +177,13 @@ const char *popup_info_text(struct tile 
   }
   if (punit && !pcity) {
     struct player *owner = unit_owner(punit);
-    struct player_diplstate *ds = game.player_ptr->diplstates;
     struct unit_type *ptype = unit_type(punit);
 
-    if (owner == game.player_ptr){
+    if (!game.player_ptr || owner == game.player_ptr){
       struct city *pcity;
       char tmp[64] = {0};
 
-      pcity = player_find_city_by_id(game.player_ptr, punit->homecity);
+      pcity = player_find_city_by_id(owner, punit->homecity);
       if (pcity) {
        my_snprintf(tmp, sizeof(tmp), "/%s", pcity->name);
       }
@@ -183,6 +192,10 @@ const char *popup_info_text(struct tile 
                    get_nation_name(owner->nation),
                    tmp);
     } else if (owner) {
+      struct player_diplstate *ds = game.player_ptr->diplstates;
+
+      assert(owner != NULL && game.player_ptr != NULL);
+
       if (ds[owner->player_no].type == DS_CEASEFIRE) {
        int turns = ds[owner->player_no].turns_left;
 
@@ -201,9 +214,10 @@ const char *popup_info_text(struct tile 
       }
     }
 
-    if (owner != game.player_ptr){
-      struct unit *apunit;
-      if ((apunit = get_unit_in_focus())) {
+    if (owner){
+      struct unit *apunit = get_unit_in_focus();
+
+      if (apunit && apunit->owner != owner) {
        /* chance to win when active unit is attacking the selected unit */
        int att_chance = unit_win_chance(apunit, punit) * 100;
        
@@ -223,7 +237,7 @@ const char *popup_info_text(struct tile 
                  ptype->attack_strength, 
                  ptype->defense_strength, ptype->firepower, punit->hp, 
                  ptype->hp, punit->veteran ? _(" V") : "");
-    if (owner == game.player_ptr
+    if ((!game.player_ptr || owner == game.player_ptr)
        && unit_list_size(ptile->units) >= 2) {
       /* TRANS: "5 more" units on this tile */
       astr_add(&str, _("  (%d more)"), unit_list_size(ptile->units) - 1);
@@ -308,7 +322,7 @@ const char *unit_description(struct unit
 {
   int pcity_near_dist;
   struct city *pcity =
-      player_find_city_by_id(game.player_ptr, punit->homecity);
+      player_find_city_by_id(punit->owner, punit->homecity);
   struct city *pcity_near = get_nearest_city(punit, &pcity_near_dist);
   struct unit_type *ptype = unit_type(punit);
   static struct astring str = ASTRING_INIT;
@@ -347,6 +361,10 @@ static int get_bulbs_per_turn(int *pours
   struct player *plr = game.player_ptr;
   int ours = 0, theirs = 0;
 
+  if (!game.player_ptr) {
+    return 0;
+  }
+
   /* Sum up science */
   players_iterate(pplayer) {
     enum diplstate_type ds = pplayer_get_diplstate(plr, pplayer)->type;
@@ -383,9 +401,8 @@ const char *science_dialog_text(void)
 
   get_bulbs_per_turn(&ours, &theirs);
 
-  if (ours == 0 && theirs == 0) {
-    astr_add(&str, _("Progress: no research"));
-    return str.str;
+  if (!game.player_ptr || (ours == 0 && theirs == 0)) {
+    return _("Progress: no research");
   }
   assert(ours >= 0 && theirs >= 0);
   if (get_player_research(plr)->researching == A_UNSET) {
@@ -425,6 +442,10 @@ const char *get_science_target_text(doub
   struct player_research *research = get_player_research(game.player_ptr);
   static struct astring str = ASTRING_INIT;
 
+  if (!game.player_ptr) {
+    return "-";
+  }
+
   astr_clear(&str);
   if (research->researching == A_UNSET) {
     astr_add(&str, _("%d/- (never)"), research->bulbs_researched);
@@ -466,6 +487,10 @@ const char *get_science_goal_text(Tech_t
   struct player_research* research = get_player_research(game.player_ptr);
   static struct astring str = ASTRING_INIT;
 
+  if (!game.player_ptr) {
+    return "-";
+  }
+
   astr_clear(&str);
 
   if (is_tech_a_req_for_goal(game.player_ptr,
@@ -535,21 +560,25 @@ const char *get_info_label_text_popup(vo
 
   astr_clear(&str);
 
-  astr_add_line(&str, _("%s People"),
-               population_to_text(civ_population(game.player_ptr)));
+  if (game.player_ptr) {
+    astr_add_line(&str, _("%s People"),
+                 population_to_text(civ_population(game.player_ptr)));
+  }
   astr_add_line(&str, _("Year: %s"), textyear(game.info.year));
   astr_add_line(&str, _("Turn: %d"), game.info.turn);
-  astr_add_line(&str, _("Gold: %d"), game.player_ptr->economic.gold);
-  astr_add_line(&str, _("Net Income: %d"),
-               player_get_expected_income(game.player_ptr));
-  /* TRANS: Gold, luxury, and science rates are in percentage values. */
-  astr_add_line(&str, _("Tax rates: Gold:%d%% Luxury:%d%% Science:%d%%"),
-               game.player_ptr->economic.tax,
-               game.player_ptr->economic.luxury,
-               game.player_ptr->economic.science);
-  astr_add_line(&str, _("Researching %s: %s"),
-               get_tech_name(game.player_ptr, research->researching),
-               get_science_target_text(NULL));
+  if (game.player_ptr) {
+    astr_add_line(&str, _("Gold: %d"), game.player_ptr->economic.gold);
+    astr_add_line(&str, _("Net Income: %d"),
+                 player_get_expected_income(game.player_ptr));
+    /* TRANS: Gold, luxury, and science rates are in percentage values. */
+    astr_add_line(&str, _("Tax rates: Gold:%d%% Luxury:%d%% Science:%d%%"),
+                 game.player_ptr->economic.tax,
+                 game.player_ptr->economic.luxury,
+                 game.player_ptr->economic.science);
+    astr_add_line(&str, _("Researching %s: %s"),
+                 get_tech_name(game.player_ptr, research->researching),
+                 get_science_target_text(NULL));
+  }
 
   /* These mirror the code in get_global_warming_tooltip and
    * get_nuclear_winter_tooltip. */
@@ -560,8 +589,10 @@ const char *get_info_label_text_popup(vo
                CLIP(0, (game.info.nuclearwinter + 1) / 2, 100),
                DIVIDE(game.info.cooling - game.info.coolinglevel + 1, 2));
 
-  astr_add_line(&str, _("Government: %s"),
-               get_government_name(game.player_ptr->government));
+  if (game.player_ptr) {
+    astr_add_line(&str, _("Government: %s"),
+                 get_government_name(game.player_ptr->government));
+  }
 
   return str.str;
 }
@@ -600,7 +631,7 @@ const char *get_unit_info_label_text2(st
    * GUI widgets may be confused and try to resize themselves. */
   if (punit) {
     struct city *pcity =
-       player_find_city_by_id(game.player_ptr, punit->homecity);
+       player_find_city_by_id(punit->owner, punit->homecity);
     int infracount;
     bv_special infrastructure =
       get_tile_infrastructure_set(punit->tile, &infracount);
@@ -851,7 +882,9 @@ const char *get_score_text(const struct 
 
   astr_clear(&str);
 
-  if (pplayer->score.game > 0 || pplayer == game.player_ptr) {
+  if (pplayer->score.game > 0
+      || !game.player_ptr
+      || pplayer == game.player_ptr) {
     astr_add(&str, "%d", pplayer->score.game);
   } else {
     astr_add(&str, "?");
@@ -873,17 +906,23 @@ const char *get_report_title(const char 
 
   astr_add_line(&str, "%s", report_name);
 
-  /* TRANS: "Republic of the Polish" */
-  astr_add_line(&str, _("%s of the %s"),
-               get_government_name(game.player_ptr->government),
-               get_nation_name_plural(game.player_ptr->nation));
-
-  astr_add_line(&str, "%s %s: %s",
-               get_ruler_title(game.player_ptr->government,
-                               game.player_ptr->is_male,
-                               game.player_ptr->nation),
-               game.player_ptr->name,
-               textyear(game.info.year));
+  if (game.player_ptr) {
+    /* TRANS: "Republic of the Polish" */
+    astr_add_line(&str, _("%s of the %s"),
+                 get_government_name(game.player_ptr->government),
+                 get_nation_name_plural(game.player_ptr->nation));
+
+    astr_add_line(&str, "%s %s: %s",
+                 get_ruler_title(game.player_ptr->government,
+                                 game.player_ptr->is_male,
+                                 game.player_ptr->nation),
+                 game.player_ptr->name,
+                 textyear(game.info.year));
+  } else {
+    /* TRANS: "Observer: 1985" */
+    astr_add_line(&str, _("Observer: %s"),
+                 textyear(game.info.year));
+  }
   return str.str;
 }
 
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.322
diff -p -u -r1.322 tilespec.c
--- client/tilespec.c   25 Aug 2005 18:57:22 -0000      1.322
+++ client/tilespec.c   6 Sep 2005 22:01:43 -0000
@@ -3617,8 +3617,10 @@ static int fill_grid_sprite_array(const 
        && base_map_to_city_map(&dummy_x, &dummy_y, pfocus->tile, tile);
       worked[i] = FALSE;
 
-      city[i] = tile && (powner == NULL || powner == game.player_ptr)
-       && player_in_city_radius(game.player_ptr, tile);
+      city[i] = (tile
+                && (!powner || !game.player_ptr || powner == game.player_ptr)
+                && (!game.player_ptr
+                    || player_in_city_radius(game.player_ptr, tile)));
       if (city[i]) {
        if (citymode) {
          int cx, cy;
@@ -4226,7 +4228,7 @@ struct unit *get_drawable_unit(const str
   if (!punit)
     return NULL;
 
-  if (citymode && punit->owner == game.player_ptr)
+  if (citymode && punit->owner == citymode->owner)
     return NULL;
 
   if (punit != pfocus
Index: client/gui-gtk-2.0/citydlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/citydlg.c,v
retrieving revision 1.140
diff -p -u -r1.140 citydlg.c
--- client/gui-gtk-2.0/citydlg.c        8 Aug 2005 16:15:29 -0000       1.140
+++ client/gui-gtk-2.0/citydlg.c        6 Sep 2005 22:01:44 -0000
@@ -375,7 +375,7 @@ void refresh_city_dialog(struct city *pc
   city_dialog_update_supported_units(pdialog);
   city_dialog_update_present_units(pdialog);
 
-  if (city_owner(pcity) == game.player_ptr) {
+  if (!game.player_ptr || city_owner(pcity) == game.player_ptr) {
     bool have_present_units =
        (unit_list_size(pcity->tile->units) > 0);
     refresh_worklist(pdialog->production.worklist);
@@ -870,7 +870,7 @@ target_drag_data_received(GtkWidget *w, 
   GtkTreeModel *model;
   GtkTreePath *path;
 
-  if (pdialog->pcity->owner != game.player_ptr) {
+  if (game.player_ptr && pdialog->pcity->owner != game.player_ptr) {
     gtk_drag_finish(context, FALSE, FALSE, time);
   }
     
@@ -1224,7 +1224,7 @@ static struct city_dialog *create_city_d
   create_and_append_worklist_page(pdialog);
 
   /* only create these tabs if not a spy */
-  if (pcity->owner == game.player_ptr) {
+  if (!game.player_ptr || pcity->owner == game.player_ptr) {
     create_and_append_happiness_page(pdialog);
     create_and_append_cma_page(pdialog);
   }
@@ -1263,7 +1263,7 @@ static struct city_dialog *create_city_d
   gtk_dialog_add_action_widget(GTK_DIALOG(pdialog->shell),
                               pdialog->next_command, 2);
   
-  if (pcity->owner != game.player_ptr) {
+  if (!game.player_ptr || pcity->owner != game.player_ptr) {
     gtk_widget_set_sensitive(pdialog->prev_command, FALSE);
     gtk_widget_set_sensitive(pdialog->next_command, FALSE);
   }
@@ -1633,7 +1633,7 @@ static void city_dialog_update_supported
   int n, m, i;
   char buf[30];
 
-  if (pdialog->pcity->owner != game.player_ptr) {
+  if (game.player_ptr && pdialog->pcity->owner != game.player_ptr) {
     units = pdialog->pcity->info_units_supported;
   } else {
     units = pdialog->pcity->units_supported;
@@ -1752,7 +1752,7 @@ static void city_dialog_update_present_u
   int n, m, i;
   char buf[30];
 
-  if (pdialog->pcity->owner != game.player_ptr) {
+  if (game.player_ptr && pdialog->pcity->owner != game.player_ptr) {
     units = pdialog->pcity->info_units_present;
   } else {
     units = pdialog->pcity->tile->units;
@@ -1866,7 +1866,13 @@ static void city_dialog_update_present_u
 static void city_dialog_update_prev_next()
 {
   int count = 0;
-  int city_number = city_list_size(game.player_ptr->cities);
+  int city_number;
+
+  if (game.player_ptr) {
+    city_number = city_list_size(game.player_ptr->cities);
+  } else {
+    city_number = FC_INFINITY; /* ? */
+  }
 
   /* the first time, we see if all the city dialogs are open */
 
@@ -2105,7 +2111,8 @@ static gboolean present_unit_callback(Gt
       GINT_TO_POINTER(punit->id));
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
 
-    if (can_upgrade_unittype(game.player_ptr, punit->type) == NULL) {
+    if (!can_client_issue_orders()
+       || can_upgrade_unittype(game.player_ptr, punit->type) == NULL) {
       gtk_widget_set_sensitive(item, FALSE);
     }
 
@@ -2411,12 +2418,14 @@ static void buy_callback_response(GtkWid
 *****************************************************************/
 static void buy_callback(GtkWidget *w, gpointer data)
 {
-  struct city_dialog *pdialog;
+  struct city_dialog *pdialog = data;
   int value;
   const char *name;
   GtkWidget *shell;
 
-  pdialog = (struct city_dialog *) data;
+  if (!can_client_issue_orders()) {
+    return;
+  }
 
   if (pdialog->pcity->production.is_unit) {
     name = get_unit_type(pdialog->pcity->production.value)->name;
@@ -2718,10 +2727,8 @@ static void city_destroy_callback(GtkWid
 
   gtk_widget_hide(pdialog->shell);
 
-  if (pdialog->pcity->owner == game.player_ptr) {
-    close_happiness_dialog(pdialog->pcity);
-    close_cma_dialog(pdialog->pcity);
-  }
+  close_happiness_dialog(pdialog->pcity);
+  close_cma_dialog(pdialog->pcity);
 
   citydialog_height = pdialog->shell->allocation.height;
   citydialog_width = pdialog->shell->allocation.width;
@@ -2787,9 +2794,14 @@ static void close_city_dialog(struct cit
 static void switch_city_callback(GtkWidget *w, gpointer data)
 {
   struct city_dialog *pdialog = (struct city_dialog *) data;
-  int i, j, dir, size = city_list_size(game.player_ptr->cities);
+  int i, j, dir, size;
   struct city *new_pcity = NULL;
 
+  if (!game.player_ptr) {
+    return;
+  }
+  size = city_list_size(game.player_ptr->cities);
+
   assert(city_dialogs_have_been_initialised);
   assert(size >= 1);
   assert(pdialog->pcity->owner == game.player_ptr);
Index: client/gui-gtk-2.0/cityrep.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/cityrep.c,v
retrieving revision 1.79
diff -p -u -r1.79 cityrep.c
--- client/gui-gtk-2.0/cityrep.c        8 Aug 2005 16:15:29 -0000       1.79
+++ client/gui-gtk-2.0/cityrep.c        6 Sep 2005 22:01:44 -0000
@@ -535,6 +535,9 @@ static void append_cma_to_menu_item(GtkM
   GtkWidget *w;
 
   gtk_menu_item_remove_submenu(parent_item);
+  if (!can_client_issue_orders()) {
+    return;
+  }
   menu = gtk_menu_new();
   gtk_menu_item_set_submenu(parent_item, menu);
 
@@ -1099,8 +1102,7 @@ static void update_row(GtkTreeIter *row,
 *****************************************************************/
 static void city_model_init(void)
 {
-  if (city_dialog_shell && !is_report_dialogs_frozen()) {
-
+  if (city_dialog_shell && !is_report_dialogs_frozen() && game.player_ptr) {
     city_list_iterate(game.player_ptr->cities, pcity) {
       GtkTreeIter it;
 
@@ -1138,14 +1140,16 @@ void city_report_dialog_update(void)
     /* update. */
     gtk_list_store_clear(city_model);
 
-    city_list_iterate(game.player_ptr->cities, pcity) {
-      gtk_list_store_append(city_model, &it);
-      update_row(&it, pcity);
+    if (game.player_ptr) {
+      city_list_iterate(game.player_ptr->cities, pcity) {
+       gtk_list_store_append(city_model, &it);
+       update_row(&it, pcity);
 
-      if (g_hash_table_remove(copy, pcity)) {
-       gtk_tree_selection_select_iter(city_selection, &it);
-      }
-    } city_list_iterate_end;
+       if (g_hash_table_remove(copy, pcity)) {
+         gtk_tree_selection_select_iter(city_selection, &it);
+       }
+      } city_list_iterate_end;
+    }
 
     /* free the selection. */
     g_hash_table_destroy(copy);
Index: client/gui-gtk-2.0/diplodlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/diplodlg.c,v
retrieving revision 1.33
diff -p -u -r1.33 diplodlg.c
--- client/gui-gtk-2.0/diplodlg.c       1 Aug 2005 06:44:44 -0000       1.33
+++ client/gui-gtk-2.0/diplodlg.c       6 Sep 2005 22:01:44 -0000
@@ -20,28 +20,30 @@
 
 #include <gtk/gtk.h>
 
+#include "mem.h"
+#include "shared.h"
+#include "support.h"
+
+#include "diptreaty.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
 #include "map.h"
-#include "mem.h"
 #include "packets.h"
 #include "player.h"
-#include "shared.h"
-#include "support.h"
 
 #include "chatline.h"
+#include "civclient.h"
 #include "climisc.h"
 #include "clinet.h"
-#include "diptreaty.h"
+#include "options.h"
+
+#include "diplodlg.h"
 #include "gui_main.h"
 #include "gui_stuff.h"
 #include "mapview.h"
-#include "options.h"
 #include "plrdlg.h"
 
-#include "diplodlg.h"
-
 #define MAX_NUM_CLAUSES 64
 
 struct Diplomacy_dialog {
@@ -170,6 +172,10 @@ static void popup_diplomacy_dialog(int o
 {
   struct Diplomacy_dialog *pdialog = find_diplomacy_dialog(other_player_id);
 
+  if (!can_client_issue_orders()) {
+    return;
+  }
+
   if (game.player_ptr->ai.control) {
     return;                    /* Don't show if we are AI controlled. */
   }
Index: client/gui-gtk-2.0/gamedlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gamedlgs.c,v
retrieving revision 1.30
diff -p -u -r1.30 gamedlgs.c
--- client/gui-gtk-2.0/gamedlgs.c       2 May 2005 08:45:19 -0000       1.30
+++ client/gui-gtk-2.0/gamedlgs.c       6 Sep 2005 22:01:44 -0000
@@ -22,23 +22,25 @@
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
+#include "shared.h"
+#include "support.h"
+
 #include "events.h"
 #include "fcintl.h"
 #include "game.h"
 #include "government.h"
 #include "packets.h"
 #include "player.h"
-#include "shared.h"
-#include "support.h"
+
+#include "civclient.h"
+#include "clinet.h"
+#include "options.h"
 
 #include "chatline.h"
 #include "cityrep.h"
 #include "dialogs.h"
-#include "clinet.h"
 #include "gui_main.h"
 #include "gui_stuff.h"
-#include "options.h"
-
 #include "ratesdlg.h"
 #include "optiondlg.h"
 
@@ -73,7 +75,11 @@ static void rates_set_values(int tax, in
   lux_lock     = GTK_TOGGLE_BUTTON(rates_lux_toggle)->active;
   sci_lock     = GTK_TOGGLE_BUTTON(rates_sci_toggle)->active;
 
-  maxrate = get_player_bonus(game.player_ptr, EFT_MAX_RATES);
+  if (game.player_ptr) {
+    maxrate = get_player_bonus(game.player_ptr, EFT_MAX_RATES);
+  } else {
+    maxrate = 100;
+  }
   /* This's quite a simple-minded "double check".. */
   tax=MIN(tax, maxrate);
   lux=MIN(lux, maxrate);
@@ -213,6 +219,10 @@ static GtkWidget *create_rates_dialog(vo
   GtkWidget    *frame, *hbox;
 
   GtkWidget    *scale;
+
+  if (!can_client_issue_orders()) {
+    return NULL;
+  }
   
   shell = gtk_dialog_new_with_buttons(_("Select tax, luxury and science 
rates"),
        NULL,
@@ -330,8 +340,16 @@ void popup_rates_dialog(void)
 {
   char buf[64];
 
-  if (!rates_dialog_shell)
+  if (!can_client_issue_orders()) {
+    return;
+  }
+
+  if (!rates_dialog_shell) {
     rates_dialog_shell = create_rates_dialog();
+  }
+  if (!rates_dialog_shell) {
+    return;
+  }
 
   my_snprintf(buf, sizeof(buf), _("%s max rate: %d%%"),
       get_government_name(game.player_ptr->government),
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/gui_main.c,v
retrieving revision 1.137
diff -p -u -r1.137 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       29 Aug 2005 13:56:49 -0000      1.137
+++ client/gui-gtk-2.0/gui_main.c       6 Sep 2005 22:01:45 -0000
@@ -384,7 +384,7 @@ static gboolean keyboard_handler(GtkWidg
     return TRUE;
   }
 
-  if (!client_is_observer()) {
+  if (!aconnection.observer) {
     if ((ev->state & GDK_SHIFT_MASK)) {
       switch (ev->keyval) {
        case GDK_Left:
@@ -1260,9 +1260,6 @@ void update_conn_list_dialog(void)
     players_iterate(pplayer) {
       enum cmdlevel_id access_level = ALLOW_NONE;
 
-      if (pplayer->is_observer) {
-       continue; /* Connections are listed individually. */
-      }
       conn_list_iterate(pplayer->connections, pconn) {
         access_level = MAX(pconn->access_level, access_level);
       } conn_list_iterate_end;
@@ -1309,7 +1306,7 @@ void update_conn_list_dialog(void)
                         -1);
     } players_iterate_end;
     conn_list_iterate(game.est_connections, pconn) {
-      if (pconn->player && !pconn->observer && !pconn->player->is_observer) {
+      if (pconn->player && !pconn->observer) {
        continue; /* Already listed above. */
       }
       sz_strlcpy(name, pconn->username);
Index: client/gui-gtk-2.0/happiness.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/happiness.c,v
retrieving revision 1.23
diff -p -u -r1.23 happiness.c
--- client/gui-gtk-2.0/happiness.c      4 Jul 2005 17:48:37 -0000       1.23
+++ client/gui-gtk-2.0/happiness.c      6 Sep 2005 22:01:45 -0000
@@ -224,8 +224,8 @@ static void happiness_dialog_update_citi
   int cities = city_list_size(pplayer->cities);
   int content = game.info.unhappysize;
   int basis = game.info.cityfactor 
-              + get_player_bonus(game.player_ptr, EFT_EMPIRE_SIZE_MOD);
-  int step = get_player_bonus(game.player_ptr, EFT_EMPIRE_SIZE_STEP);
+              + get_player_bonus(pcity->owner, EFT_EMPIRE_SIZE_MOD);
+  int step = get_player_bonus(pcity->owner, EFT_EMPIRE_SIZE_STEP);
   int excess = cities - basis;
   int penalty = 0;
 
Index: client/gui-gtk-2.0/menu.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/menu.c,v
retrieving revision 1.84
diff -p -u -r1.84 menu.c
--- client/gui-gtk-2.0/menu.c   18 Aug 2005 06:44:27 -0000      1.84
+++ client/gui-gtk-2.0/menu.c   6 Sep 2005 22:01:45 -0000
@@ -553,8 +553,10 @@ static void reports_menu_callback(gpoint
    case MENU_REPORT_DEMOGRAPHIC:
     send_report_request(REPORT_DEMOGRAPHIC);
     break;
-   case MENU_REPORT_SPACESHIP:
-    popup_spaceship_dialog(game.player_ptr);
+  case MENU_REPORT_SPACESHIP:
+    if (game.player_ptr) {
+      popup_spaceship_dialog(game.player_ptr);
+    }
     break;
   }
 }
@@ -1222,7 +1224,8 @@ void update_menus(void)
           g_signal_connect(item, "activate",
                           G_CALLBACK(government_callback), g);
 
-          if (!can_change_to_government(game.player_ptr, g)) {
+          if (!game.player_ptr
+             || !can_change_to_government(game.player_ptr, g)) {
             gtk_widget_set_sensitive(item, FALSE);
          }
 
@@ -1246,7 +1249,8 @@ void update_menus(void)
                        can_client_issue_orders());
 
     menus_set_sensitive("<main>/_Reports/S_paceship",
-                       (game.player_ptr->spaceship.state!=SSHIP_NONE));
+                       (game.player_ptr
+                        && game.player_ptr->spaceship.state != SSHIP_NONE));
 
     menus_set_active("<main>/_View/City Outlines", draw_city_outlines);
     menus_set_active("<main>/_View/Map _Grid", draw_map_grid);
@@ -1385,7 +1389,7 @@ void update_menus(void)
                    get_tile_change_menu_text(punit->tile,
                                              ACTIVITY_IRRIGATE));
       } else if (tile_has_special(punit->tile, S_IRRIGATION)
-                && player_knows_techs_with_flag(game.player_ptr,
+                && player_knows_techs_with_flag(punit->owner,
                                                 TF_FARMLAND)) {
        sz_strlcpy(irrtext, _("Bu_ild Farmland"));
       }
Index: client/gui-gtk-2.0/pages.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/pages.c,v
retrieving revision 1.40
diff -p -u -r1.40 pages.c
--- client/gui-gtk-2.0/pages.c  5 Sep 2005 15:55:45 -0000       1.40
+++ client/gui-gtk-2.0/pages.c  6 Sep 2005 22:01:45 -0000
@@ -941,7 +941,9 @@ static void start_start_callback(GtkWidg
 **************************************************************************/
 static void pick_nation_callback(GtkWidget *w, gpointer data)
 {
-  popup_races_dialog(game.player_ptr);
+  if (game.player_ptr) {
+    popup_races_dialog(game.player_ptr);
+  }
 }
 
 /**************************************************************************
Index: client/gui-gtk-2.0/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/plrdlg.c,v
retrieving revision 1.68
diff -p -u -r1.68 plrdlg.c
--- client/gui-gtk-2.0/plrdlg.c 1 Aug 2005 06:44:44 -0000       1.68
+++ client/gui-gtk-2.0/plrdlg.c 6 Sep 2005 22:01:46 -0000
@@ -146,15 +146,20 @@ static void update_players_menu(void)
       gtk_widget_set_sensitive(players_sship_command, FALSE);
     }
 
-    switch (pplayer_get_diplstate(game.player_ptr, get_player(plrno))->type) {
-    case DS_WAR:
-    case DS_NO_CONTACT:
+    if (game.player_ptr) {
+      switch (pplayer_get_diplstate(game.player_ptr,
+                                   get_player(plrno))->type) {
+      case DS_WAR:
+      case DS_NO_CONTACT:
+       gtk_widget_set_sensitive(players_war_command, FALSE);
+       break;
+      default:
+       gtk_widget_set_sensitive(players_war_command,
+                                can_client_issue_orders()
+                                && game.info.player_idx != plrno);
+      }
+    } else {
       gtk_widget_set_sensitive(players_war_command, FALSE);
-      break;
-    default:
-      gtk_widget_set_sensitive(players_war_command,
-                              can_client_issue_orders()
-                              && game.info.player_idx != plrno);
     }
 
     gtk_widget_set_sensitive(players_vision_command,
@@ -576,7 +581,7 @@ static void build_row(GtkTreeIter *it, i
 {
   struct player *plr = get_player(i);
   GdkPixbuf *pixbuf;
-  gint style, weight;
+  gint style = PANGO_STYLE_NORMAL, weight = PANGO_WEIGHT_NORMAL;
   int k;
   gchar *p;
 
@@ -610,21 +615,29 @@ static void build_row(GtkTreeIter *it, i
     -1);
 
    /* now add some eye candy ... */
-   switch (pplayer_get_diplstate(game.player_ptr, plr)->type) {
-   case DS_WAR:
-     weight = PANGO_WEIGHT_NORMAL;
-     style = PANGO_STYLE_ITALIC;
-     break;
-   case DS_ALLIANCE:
-   case DS_TEAM:
-     weight = PANGO_WEIGHT_BOLD;
-     style = PANGO_STYLE_NORMAL;
-     break;
-   default:
-     weight = PANGO_WEIGHT_NORMAL;
-     style = PANGO_STYLE_NORMAL;
-     break;
-   }
+  if (game.player_ptr) {
+    switch (pplayer_get_diplstate(game.player_ptr, plr)->type) {
+    case DS_WAR:
+      weight = PANGO_WEIGHT_NORMAL;
+      style = PANGO_STYLE_ITALIC;
+      break;
+    case DS_ALLIANCE:
+    case DS_TEAM:
+      weight = PANGO_WEIGHT_BOLD;
+      style = PANGO_STYLE_NORMAL;
+      break;
+    case DS_NEUTRAL:
+    case DS_CEASEFIRE:
+    case DS_PEACE:
+    case DS_NO_CONTACT:
+      weight = PANGO_WEIGHT_NORMAL;
+      style = PANGO_STYLE_NORMAL;
+      break;
+    case DS_LAST:
+      assert(0);
+      break;
+    }
+  }
    gtk_list_store_set(store, it,
        num_player_dlg_columns, style,
        num_player_dlg_columns + 1, weight,
Index: client/gui-gtk-2.0/repodlgs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/repodlgs.c,v
retrieving revision 1.97
diff -p -u -r1.97 repodlgs.c
--- client/gui-gtk-2.0/repodlgs.c       16 Aug 2005 06:54:53 -0000      1.97
+++ client/gui-gtk-2.0/repodlgs.c       6 Sep 2005 22:01:46 -0000
@@ -145,7 +145,8 @@ void popup_science_dialog(bool raise)
     create_science_dialog(FALSE);
   }
 
-  if (get_player_research(game.player_ptr)->tech_goal == A_UNSET
+  if (can_client_issue_orders()
+      && get_player_research(game.player_ptr)->tech_goal == A_UNSET
       && get_player_research(game.player_ptr)->researching == A_UNSET) {
     gui_dialog_alert(science_dialog_shell);
   } else {
@@ -182,7 +183,7 @@ static void button_release_event_callbac
   if (tech == A_NONE) {
     return;
   }
-  if (event->button == 1) {
+  if (event->button == 1 && can_client_issue_orders()) {
     /* LMB: set research or research goal */
     switch (get_invention(game.player_ptr, tech)) {
     case TECH_REACHABLE:
@@ -227,6 +228,7 @@ static GtkWidget *create_reqtree_diagram
   GtkAdjustment* adjustment;
   int width, height;
   int x;
+  Tech_type_id researching;
 
   get_reqtree_dimensions(reqtree, &width, &height);
 
@@ -252,8 +254,12 @@ static GtkWidget *create_reqtree_diagram
   adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(sw));
   
   /* Center on currently researched node */
-  if (find_tech_on_reqtree(reqtree,
-                           get_player_research(game.player_ptr)->researching,
+  if (game.player_ptr) {
+    researching = get_player_research(game.player_ptr)->researching;
+  } else {
+    researching = A_UNSET;
+  }
+  if (find_tech_on_reqtree(reqtree, researching,
                           &x, NULL, NULL, NULL)) {
     /* FIXME: this is just an approximation */
     gtk_adjustment_set_value(adjustment, x - 100);
@@ -397,26 +403,10 @@ void science_goal_callback(GtkWidget *wi
 static gint cmp_func(gconstpointer a_p, gconstpointer b_p)
 {
   const gchar *a_str, *b_str;
-  gchar text_a[512], text_b[512];
   gint a = GPOINTER_TO_INT(a_p), b = GPOINTER_TO_INT(b_p);
 
-  /* FIXME: future techs aren't counted this way but are handled by
-   * get_tech_name() when given a player parameter. */
-  if (!is_future_tech(a)) {
-    a_str = get_tech_name(game.player_ptr, a);
-  } else {
-    my_snprintf(text_a,sizeof(text_a), _("Future Tech. %d"),
-               a - game.control.num_tech_types);
-    a_str=text_a;
-  }
-
-  if(!is_future_tech(b)) {
-    b_str = get_tech_name(game.player_ptr, b);
-  } else {
-    my_snprintf(text_b,sizeof(text_b), _("Future Tech. %d"),
-               b - game.control.num_tech_types);
-    b_str=text_b;
-  }
+  a_str = get_tech_name(game.player_ptr, a);
+  b_str = get_tech_name(game.player_ptr, b);
 
   return strcmp(a_str,b_str);
 }
@@ -434,7 +424,7 @@ void science_dialog_update(void)
   GtkSizeGroup *group1, *group2;
   struct player_research *research = get_player_research(game.player_ptr);
 
-  if (is_report_dialogs_frozen()) {
+  if (!game.player_ptr || !research || is_report_dialogs_frozen()) {
     return;
   }
 
@@ -1069,14 +1059,10 @@ static void activeunits_selection_callba
                                      ACTIVEUNITS_NEAREST,
                                      can_client_issue_orders());       
     
-    if (can_upgrade_unittype(game.player_ptr, utype) != NULL) {
-      gui_dialog_set_response_sensitive(activeunits_dialog_shell,
-                                       ACTIVEUNITS_UPGRADE,
-                                       can_client_issue_orders());     
-    } else {
-      gui_dialog_set_response_sensitive(activeunits_dialog_shell,
-                                       ACTIVEUNITS_UPGRADE, FALSE);
-    }
+    gui_dialog_set_response_sensitive(activeunits_dialog_shell,
+               ACTIVEUNITS_UPGRADE,
+               (can_client_issue_orders()
+                && can_upgrade_unittype(game.player_ptr, utype) != NULL));
   }
 }
 
@@ -1087,9 +1073,12 @@ static struct unit *find_nearest_unit(co
                                      struct tile *ptile)
 {
   struct unit *best_candidate;
-  int best_dist = 99999;
+  int best_dist = FC_INFINITY;
 
   best_candidate = NULL;
+  if (!game.player_ptr) {
+    return NULL;
+  }
   unit_list_iterate(game.player_ptr->units, punit) {
     if (punit->type == type) {
       if (punit->focus_status==FOCUS_AVAIL
@@ -1153,7 +1142,7 @@ static void activeunits_command_callback
        }
       }
     }
-  } else {
+  } else if (can_client_issue_orders()) {
     GtkWidget *shell;
     struct unit_type *ut2 = can_upgrade_unittype(game.player_ptr, utype1);
 
@@ -1189,10 +1178,12 @@ void activeunits_report_dialog_update(vo
     int building_count;
   };
 
-  if (is_report_dialogs_frozen())
+  if (is_report_dialogs_frozen() || !activeunits_dialog_shell) {
     return;
+  }
 
-  if (activeunits_dialog_shell) {
+  gtk_list_store_clear(activeunits_store);
+  if (game.player_ptr) {
     int    k, can;
     struct repoinfo unitarray[U_LAST];
     struct repoinfo unittotals;
Index: client/gui-gtk-2.0/wldlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/wldlg.c,v
retrieving revision 1.52
diff -p -u -r1.52 wldlg.c
--- client/gui-gtk-2.0/wldlg.c  8 Aug 2005 16:15:29 -0000       1.52
+++ client/gui-gtk-2.0/wldlg.c  6 Sep 2005 22:01:46 -0000
@@ -117,7 +117,11 @@ void update_worklist_report_dialog(void)
   plr = game.player_ptr;
 
   gtk_list_store_clear(worklists_store);
-  
+
+  if (!game.player_ptr) {
+    return;
+  }
+
   for (i = 0; i < MAX_NUM_WORKLISTS; i++) {
     if (plr->worklists[i].is_valid) {
       gtk_list_store_append(worklists_store, &it);
@@ -143,6 +147,10 @@ static void worklists_response(GtkWidget
 
   plr = game.player_ptr;
 
+  if (!game.player_ptr) {
+    return;
+  }
+
   for (i = 0; i < MAX_NUM_WORKLISTS; i++) {
     if (!plr->worklists[i].is_valid) {
       break;
@@ -209,13 +217,12 @@ static void cell_edited(GtkCellRendererT
   GtkTreePath *path;
   GtkTreeIter it;
   int pos;
-  struct player *plr;
+  struct player *plr = game.player_ptr;
 
   path = gtk_tree_path_new_from_string(spath);
   gtk_tree_model_get_iter(GTK_TREE_MODEL(worklists_store), &it, path);
   
   gtk_tree_model_get(GTK_TREE_MODEL(worklists_store), &it, 1, &pos, -1);
-  plr = game.player_ptr;
 
   sz_strlcpy(plr->worklists[pos].name, text);
   gtk_list_store_set(worklists_store, &it, 0, text, -1);
@@ -473,6 +480,10 @@ static void menu_item_callback(GtkMenuIt
   gint pos;
   struct worklist *pwl;
 
+  if (!game.player_ptr) {
+    return;
+  }
+
   plr = game.player_ptr;
   pos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "pos"));
 
@@ -508,6 +519,10 @@ static void popup_add_menu(GtkMenuShell 
                        (GtkCallback) gtk_widget_destroy, NULL);
   plr = game.player_ptr;
 
+  if (!game.player_ptr) {
+    return;
+  }
+
   for (i = 0; i < MAX_NUM_WORKLISTS; i++) {
     if (plr->worklists[i].is_valid) {
       item = gtk_menu_item_new_with_label(plr->worklists[i].name);
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.237
diff -p -u -r1.237 game.c
--- common/game.c       4 Sep 2005 04:31:17 -0000       1.237
+++ common/game.c       6 Sep 2005 22:01:47 -0000
@@ -435,7 +435,6 @@ void game_advance_year(void)
 ****************************************************************************/
 void game_remove_player(struct player *pplayer)
 {
-  player_set_nation(pplayer, NULL);
   if (pplayer->attribute_block.data) {
     free(pplayer->attribute_block.data);
     pplayer->attribute_block.data = NULL;
@@ -467,6 +466,9 @@ void game_remove_player(struct player *p
   city_list_free(pplayer->cities);
   pplayer->cities = NULL;
 
+  /* This comes last because log calls in the above functions may use it. */
+  player_set_nation(pplayer, NULL);
+
   if (is_barbarian(pplayer)) game.info.nbarbarians--;
 }
 
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.199
diff -p -u -r1.199 game.h
--- common/game.h       5 Sep 2005 15:55:46 -0000       1.199
+++ common/game.h       6 Sep 2005 22:01:47 -0000
@@ -71,7 +71,7 @@ struct civ_game {
   bool simultaneous_phases_stored;
   int aifill;
   char *startmessage;
-  struct player *player_ptr;
+  struct player *player_ptr; /* Client-only; may be NULL */
   struct player players[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
   struct conn_list *all_connections;        /* including not yet established */
   struct conn_list *est_connections;        /* all established client conns */
Index: common/nation.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/nation.c,v
retrieving revision 1.56
diff -p -u -r1.56 nation.c
--- common/nation.c     18 Jul 2005 22:46:28 -0000      1.56
+++ common/nation.c     6 Sep 2005 22:01:47 -0000
@@ -124,20 +124,6 @@ bool is_nation_playable(const struct nat
 }
 
 /****************************************************************************
-  Return whether a nation is usable as an observer.  If true then observers
-  can use this nation.
-
-  This does not check whether a nation is "used" or "available".
-****************************************************************************/
-bool is_nation_observer(const struct nation_type *nation)
-{
-  if (!bounds_check_nation(nation, LOG_FATAL, "is_nation_observer")) {
-    die("wrong nation %d", nation->index);
-  }
-  return nation->is_observer;
-}
-
-/****************************************************************************
   Return whether a nation is usable as a barbarian.  If true then barbarians
   can use this nation.
 
Index: common/nation.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/nation.h,v
retrieving revision 1.56
diff -p -u -r1.56 nation.h
--- common/nation.h     4 Sep 2005 04:31:17 -0000       1.56
+++ common/nation.h     6 Sep 2005 22:01:47 -0000
@@ -77,7 +77,7 @@ struct nation_type {
   struct city_name *city_names;                /* The default city names. */
   char *legend;                                /* may be empty */
 
-  bool is_playable, is_barbarian, is_observer;
+  bool is_playable, is_barbarian;
 
   /* civilwar_nations is a NO_NATION_SELECTED-terminated list of index of
    * the nations that can fork from this one.  parent_nations is the inverse
@@ -111,7 +111,6 @@ const char *get_nation_name(const struct
 const char *get_nation_name_plural(const struct nation_type *nation);
 const char *get_nation_name_orig(const struct nation_type *nation);
 bool is_nation_playable(const struct nation_type *nation);
-bool is_nation_observer(const struct nation_type *nation);
 bool is_nation_barbarian(const struct nation_type *nation);
 struct leader *get_nation_leaders(const struct nation_type *nation, int *dim);
 struct nation_type **get_nation_civilwar(const struct nation_type *nation);
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.155
diff -p -u -r1.155 packets.def
--- common/packets.def  4 Sep 2005 04:31:17 -0000       1.155
+++ common/packets.def  6 Sep 2005 22:01:48 -0000
@@ -636,7 +636,6 @@ PACKET_PLAYER_INFO=39; sc
   STRING username[MAX_LEN_NAME];
 
   UINT32 score;
-  BOOL is_observer;
   BOOL is_male;
   GOVERNMENT government;
   GOVERNMENT target_government;
@@ -1178,7 +1177,7 @@ PACKET_RULESET_NATION=102;sc,lsend,is-in
   STRING leader_name[MAX_NUM_LEADERS:leader_count][MAX_LEN_NAME];
   BOOL leader_sex[MAX_NUM_LEADERS:leader_count];
 
-  BOOL is_available, is_playable, is_observer, is_barbarian;
+  BOOL is_available, is_playable, is_barbarian;
   
   UINT8 group_count;
   STRING group_name[MAX_NUM_NATION_GROUPS:group_count][MAX_LEN_NAME];
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.192
diff -p -u -r1.192 player.c
--- common/player.c     4 Sep 2005 04:31:17 -0000       1.192
+++ common/player.c     6 Sep 2005 22:01:48 -0000
@@ -127,7 +127,6 @@ void player_init(struct player *plr)
   plr->connections = conn_list_new();
   plr->current_conn = NULL;
   plr->is_connected = FALSE;
-  plr->is_observer = FALSE;
   plr->was_created = FALSE;
   plr->is_alive=TRUE;
   plr->is_dying = FALSE;
@@ -359,6 +358,8 @@ bool can_player_see_city_internals(const
  If the specified player owns the city with the specified id,
  return pointer to the city struct.  Else return NULL.
  Now always uses fast idex_lookup_city.
+
+  pplayer will be NULL in which case all cities will be considered.
 ***************************************************************/
 struct city *player_find_city_by_id(const struct player *pplayer,
                                    int city_id)
@@ -372,6 +373,8 @@ struct city *player_find_city_by_id(cons
  If the specified player owns the unit with the specified id,
  return pointer to the unit struct.  Else return NULL.
  Uses fast idex_lookup_city.
+
+  pplayer will be NULL in which case all units will be considered.
 ***************************************************************/
 struct unit *player_find_unit_by_id(const struct player *pplayer,
                                    int unit_id)
@@ -499,6 +502,10 @@ Locate the city where the players palace
 **************************************************************************/
 struct city *find_palace(const struct player *pplayer)
 {
+  if (!pplayer) {
+    /* The client depends on this behavior in some places. */
+    return NULL;
+  }
   city_list_iterate(pplayer->cities, pcity) {
     if (is_capital(pcity)) {
       return pcity;
@@ -763,6 +770,9 @@ bool is_valid_username(const char *name)
 ****************************************************************************/
 struct player_research *get_player_research(const struct player *plr)
 {
-  assert((plr != NULL) && (plr->team != NULL));
+  if (!plr || !plr->team) {
+    /* Some client users depend on this behavior. */
+    return NULL;
+  }
   return &(plr->team->research);
 }
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.164
diff -p -u -r1.164 player.h
--- common/player.h     4 Sep 2005 04:31:18 -0000       1.164
+++ common/player.h     6 Sep 2005 22:01:48 -0000
@@ -29,7 +29,6 @@
 
 #define ANON_PLAYER_NAME "noname"
 #define ANON_USER_NAME  "Unassigned"
-#define OBSERVER_NAME  "Observer"
 
 /*
  * pplayer->ai.barbarian_type uses this enum. Note that the values
@@ -162,7 +161,6 @@ struct player {
   bool phase_done;
   int nturns_idle;
   bool is_alive;
-  bool is_observer; /* is the player a global observer */ 
   bool is_dying; /* set once the player is in the process of dying */
   bool surrendered; /* has indicated willingness to surrender */
 
@@ -182,7 +180,7 @@ struct player {
   struct player_spaceship spaceship;
   struct player_ai ai;
   bool was_created;                    /* if the player was /created */
-  bool is_connected;                  /* observers don't count */
+  bool is_connected;
   struct connection *current_conn;     /* non-null while handling packet */
   struct conn_list *connections;       /* will replace conn */
   struct worklist worklists[MAX_NUM_WORKLISTS];
Index: common/tech.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/tech.c,v
retrieving revision 1.100
diff -p -u -r1.100 tech.c
--- common/tech.c       2 Sep 2005 23:12:40 -0000       1.100
+++ common/tech.c       6 Sep 2005 22:01:48 -0000
@@ -52,6 +52,8 @@ static const char *flag_names[] = {
   Returns state of the tech for current pplayer.
   This can be: TECH_KNOW, TECH_UNKNOWN or TECH_REACHABLE
   Should be called with existing techs or A_FUTURE
+
+  If pplayer is NULL this simply returns TECH_KNOWN (used by the client).
 **************************************************************************/
 enum tech_state get_invention(const struct player *pplayer,
                              Tech_type_id tech)
@@ -59,7 +61,11 @@ enum tech_state get_invention(const stru
   assert(tech == A_FUTURE
          || (tech >= 0 && tech < game.control.num_tech_types));
 
-  return get_player_research(pplayer)->inventions[tech].state;
+  if (!pplayer) {
+    return TECH_KNOWN;
+  } else {
+    return get_player_research(pplayer)->inventions[tech].state;
+  }
 }
 
 /**************************************************************************
@@ -84,12 +90,18 @@ void set_invention(struct player *pplaye
 /**************************************************************************
   Returns if the given tech has to be researched to reach the
   goal. The goal itself isn't a requirement of itself.
+
+  pplayer may be NULL; however the function will always return FALSE in
+  that case.
 **************************************************************************/
 bool is_tech_a_req_for_goal(const struct player *pplayer, Tech_type_id tech,
                            Tech_type_id goal)
 {
   if (tech == goal) {
     return FALSE;
+  } else if (!pplayer) {
+    /* FIXME: We need a proper implementation here! */
+    return FALSE;
   } else {
     return
       BV_ISSET(get_player_research(pplayer)->inventions[goal].required_techs,
@@ -177,6 +189,9 @@ static void build_required_techs(struct 
 /**************************************************************************
   Returns TRUE iff the given tech is ever reachable by the given player
   by checking tech tree limitations.
+
+  pplayer may be NULL in which case a simplified result is returned
+  (used by the client).
 **************************************************************************/
 bool tech_is_available(const struct player *pplayer, Tech_type_id id)
 {
@@ -390,6 +405,9 @@ int total_bulbs_required(const struct pl
 
   At the end we multiply by the sciencebox value, as a percentage.  The
   cost can never be less than 1.
+
+  pplayer may be NULL in which case a simplified result is returned (used
+  by client and manual code).
 ****************************************************************************/
 int base_total_bulbs_required(const struct player *pplayer,
                              Tech_type_id tech)
@@ -397,7 +415,9 @@ int base_total_bulbs_required(const stru
   int tech_cost_style = game.info.tech_cost_style;
   double base_cost;
 
-  if (!is_future_tech(tech) && get_invention(pplayer, tech) == TECH_KNOWN) {
+  if (pplayer
+      && !is_future_tech(tech)
+      && get_invention(pplayer, tech) == TECH_KNOWN) {
     /* A non-future tech which is already known costs nothing. */
     return 0;
   }
@@ -414,8 +434,12 @@ int base_total_bulbs_required(const stru
 
   switch (tech_cost_style) {
   case 0:
-    base_cost = get_player_research(pplayer)->techs_researched 
-                * game.info.base_tech_cost;
+    if (pplayer) {
+      base_cost = get_player_research(pplayer)->techs_researched 
+       * game.info.base_tech_cost;
+    } else {
+      base_cost = 0;
+    }
     break;
   case 1:
     base_cost = techcoststyle1[tech];
@@ -447,7 +471,7 @@ int base_total_bulbs_required(const stru
       players_iterate(other) {
        players++;
        if (get_invention(other, tech) == TECH_KNOWN
-           && player_has_embassy(pplayer, other)) {
+           && pplayer && player_has_embassy(pplayer, other)) {
          players_with_tech_and_embassy++;
        }
       } players_iterate_end;
@@ -500,7 +524,7 @@ int base_total_bulbs_required(const stru
    * can also be adpoted to create an extra-hard AI skill level where the AI
    * gets science benefits */
 
-  if (pplayer->ai.control) {
+  if (pplayer && pplayer->ai.control) {
     assert(pplayer->ai.science_cost > 0);
     base_cost *= (double)pplayer->ai.science_cost / 100.0;
   }
@@ -514,10 +538,16 @@ int base_total_bulbs_required(const stru
  Returns the number of technologies the player need to research to get
  the goal technology. This includes the goal technology. Technologies
  are only counted once.
+
+  pplayer may be NULL; however the wrong value will be return in this case.
 **************************************************************************/
 int num_unknown_techs_for_goal(const struct player *pplayer,
                               Tech_type_id goal)
 {
+  if (!pplayer) {
+    /* FIXME: need an implementation for this! */
+    return 0;
+  }
   return get_player_research(pplayer)->inventions[goal].num_required_techs;
 }
 
@@ -525,10 +555,16 @@ int num_unknown_techs_for_goal(const str
  Function to determine cost (in bulbs) of reaching goal
  technology. These costs _include_ the cost for researching the goal
  technology itself.
+
+  pplayer may be NULL; however the wrong value will be return in this case.
 **************************************************************************/
 int total_bulbs_required_for_goal(const struct player *pplayer,
                                  Tech_type_id goal)
 {
+  if (!pplayer) {
+    /* FIXME: need an implementation for this! */
+    return 0;
+  }
   return get_player_research(pplayer)->inventions[goal].bulbs_required;
 }
 
@@ -583,14 +619,15 @@ bool is_future_tech(Tech_type_id tech)
 #include "specvec.h"
 
 /**************************************************************************
- Return the name of the given tech. You don't have to free the return
- pointer.
+  Return the name of the given tech. You don't have to free the return
+  pointer.
+
+  pplayer may be NULL.  In this case we won't know the "number" of a
+  future technology.
 **************************************************************************/
 const char *get_tech_name(const struct player *pplayer, Tech_type_id tech)
 {
-  static struct string_vector future;
   int i;
-  struct player_research *research;
 
   /* We don't return a static buffer because that would break anything that
    * needed to work with more than one name at a time. */
@@ -602,22 +639,27 @@ const char *get_tech_name(const struct p
     /* TRANS: "None" tech */
     return _("None");
   case A_FUTURE:
-    research = get_player_research(pplayer);
+    if (pplayer) {
+      struct player_research *research = get_player_research(pplayer);
+      static struct string_vector future;
+
+      /* pplayer->future_tech == 0 means "Future Tech. 1". */
+      for (i = future.size; i <= research->future_tech; i++) {
+       char *ptr = NULL;
 
-    /* pplayer->future_tech == 0 means "Future Tech. 1". */
-    for (i = future.size; i <= research->future_tech; i++) {
-      char *ptr = NULL;
-
-      string_vector_append(&future, &ptr);
-    }
-    if (!future.p[research->future_tech]) {
-      char buffer[1024];
+       string_vector_append(&future, &ptr);
+      }
+      if (!future.p[research->future_tech]) {
+       char buffer[1024];
 
-      my_snprintf(buffer, sizeof(buffer), _("Future Tech. %d"),
-                 research->future_tech + 1);
-      future.p[research->future_tech] = mystrdup(buffer);
+       my_snprintf(buffer, sizeof(buffer), _("Future Tech. %d"),
+                   research->future_tech + 1);
+       future.p[research->future_tech] = mystrdup(buffer);
+      }
+      return future.p[research->future_tech];
+    } else {
+      return _("Future Tech.");
     }
-    return future.p[research->future_tech];
   default:
     /* Includes A_NONE */
     if (!tech_exists(tech)) {
Index: data/civ1/nations.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/civ1/nations.ruleset,v
retrieving revision 1.4
diff -p -u -r1.4 nations.ruleset
--- data/civ1/nations.ruleset   29 Aug 2004 19:03:32 -0000      1.4
+++ data/civ1/nations.ruleset   6 Sep 2005 22:01:48 -0000
@@ -61,8 +61,4 @@ options="1.9"
 *include "nation/english.ruleset"
 *include "nation/mongol.ruleset"
 
-;
-; observer and barbarians MUST go last in THIS order
-;
-*include "nation/observer.ruleset"
 *include "nation/barbarian.ruleset"
Index: data/default/nations.ruleset
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/default/nations.ruleset,v
retrieving revision 1.82
diff -p -u -r1.82 nations.ruleset
--- data/default/nations.ruleset        3 Sep 2005 02:06:41 -0000       1.82
+++ data/default/nations.ruleset        6 Sep 2005 22:01:48 -0000
@@ -146,8 +146,5 @@ match=2
 *include "nation/bulgarian.ruleset"
 *include "nation/inuit.ruleset"
 *include "nation/british.ruleset"
-;
-; observer and barbarians MUST go last in THIS order
-;
-*include "nation/observer.ruleset"
+
 *include "nation/barbarian.ruleset"
Index: data/nation/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/nation/Makefile.am,v
retrieving revision 1.23
diff -p -u -r1.23 Makefile.am
--- data/nation/Makefile.am     20 Aug 2005 07:06:18 -0000      1.23
+++ data/nation/Makefile.am     6 Sep 2005 22:01:49 -0000
@@ -69,7 +69,6 @@ pkgdata_DATA = \
                mordor.ruleset \
                newzealand.ruleset      \
                nigerian.ruleset \
-               observer.ruleset \
                persian.ruleset \
                phoenician.ruleset \
                polish.ruleset \
Index: server/gamehand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gamehand.c,v
retrieving revision 1.169
diff -p -u -r1.169 gamehand.c
--- server/gamehand.c   5 Sep 2005 15:55:46 -0000       1.169
+++ server/gamehand.c   6 Sep 2005 22:01:50 -0000
@@ -239,11 +239,6 @@ void init_new_game(void)
     struct start_position pos
       = map.start_positions[start_pos[pplayer->player_no]];
 
-    /* don't give any units to observer */
-    if (pplayer->is_observer) {
-      continue;
-    }
-
     /* Place the first unit. */
     place_starting_unit(pos.tile, pplayer, game.info.start_units[0]);
   } players_iterate_end;
@@ -256,11 +251,6 @@ void init_new_game(void)
     struct start_position p
       = map.start_positions[start_pos[pplayer->player_no]];
 
-    /* don't give any units to observer */
-    if (pplayer->is_observer) {
-      continue;
-    }
-
     /* Place global start units */
     for (i = 1; i < strlen(game.info.start_units); i++) {
       ptile = find_dispersed_position(pplayer, &p);
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.422
diff -p -u -r1.422 plrhand.c
--- server/plrhand.c    5 Sep 2005 15:55:47 -0000       1.422
+++ server/plrhand.c    6 Sep 2005 22:01:50 -0000
@@ -822,7 +822,7 @@ void send_player_info_c(struct player *s
       package_player_common(pplayer, &info);
 
       conn_list_iterate(dest, pconn) {
-       if (pconn->player && pconn->player->is_observer) {
+       if (!pconn->player && pconn->observer) {
          /* Global observer. */
          package_player_info(pplayer, &info, pconn->player, INFO_FULL);
        } else if (pconn->player) {
@@ -863,7 +863,6 @@ static void package_player_common(struct
   sz_strlcpy(packet->username, plr->username);
   packet->nation = plr->nation ? plr->nation->index : -1;
   packet->is_male=plr->is_male;
-  packet->is_observer=plr->is_observer;
   packet->team = plr->team ? plr->team->index : -1;
   packet->is_ready = plr->is_ready;
   packet->city_style=plr->city_style;
@@ -1369,101 +1368,6 @@ struct nation_type *pick_available_natio
 }
 
 /****************************************************************************
-  Return an available observer nation.  This simply returns the first
-  such nation.  If no nation is available NO_NATION_SELECTED is returned.
-****************************************************************************/
-static struct nation_type *pick_observer_nation(void)
-{
-  nations_iterate(pnation) {
-    if (is_nation_observer(pnation) && !pnation->player) {
-      return pnation;
-    }
-  } nations_iterate_end;
-
-  return NO_NATION_SELECTED;
-}
-
-/****************************************************************************
-  Create a player with is_observer = TRUE and return it.
-  If a global observer has already been created, return that player.
-  If there are no player slots available return NULL.
-
-  (Could be called ensure_global_observer instead.)
-****************************************************************************/
-struct player *create_global_observer(void)
-{
-  struct player *pplayer = NULL;
-  struct nation_type *nation;
-
-  /* Check if a global observer already exists. If so, return it.  Note the
-   * observer may exist at any position in the array. */
-  players_iterate(aplayer) {
-    if (aplayer->is_observer) {
-      return aplayer;
-    }
-  } players_iterate_end
-
-  /* If we're here we couldn't find an observer, so check if we have
-   * a slot available to create one.  Observers are taken from the slots of
-   * normal civs (barbarians are reserved separately). */
-  if (game.info.nplayers - game.info.nbarbarians >= MAX_NUM_PLAYERS) {
-    notify_conn(NULL, NULL, E_CONNECTION,
-               _("A global observer cannot be created: too "
-                 "many regular players."));
-    return NULL;
-  }
-
-  nation = pick_observer_nation();
-  if (nation == NO_NATION_SELECTED) {
-    notify_conn(NULL, NULL, E_CONNECTION,
-               _("A global observer cannot be created: there's "
-                 "no observer nation in the ruleset."));
-    return NULL;
-  }
-
-  /* alright, we can create an observer. go for it. */
-  pplayer = &game.players[game.info.nplayers];
-
-  /* only allocate a player map is the game is running or a game is loaded
-   * in pregame. This is because a game map might not be created otherwise.
-   *
-   * FIXME: could we use map_is_empty here? */
-  server_player_init(pplayer,
-                     (server_state == RUN_GAME_STATE || 
!game.info.is_new_game),
-                    TRUE);
-
-  sz_strlcpy(pplayer->name, OBSERVER_NAME);
-  sz_strlcpy(pplayer->username, ANON_USER_NAME);
-  pplayer->is_connected = FALSE;
-  pplayer->is_observer = TRUE;
-  pplayer->capital = TRUE;     /* is this necessary? maybe for client... */
-  pplayer->phase_done = TRUE;
-  BV_CLR_ALL(pplayer->embassy);                /* no embassies */
-  pplayer->is_alive = FALSE;
-  pplayer->was_created = FALSE;        /* doesn't really matter */
-
-  /* don't do this otherwise, because a game map might
-   * not have been created.
-   *
-   * FIXME: could we use map_is_empty here? */
-  if (server_state == RUN_GAME_STATE || !game.info.is_new_game) {
-    pplayer->nation = nation;
-    init_tech(pplayer, 0);
-    map_know_and_see_all(pplayer);
-  }
-
-  game.info.nplayers++;
-
-  /* tell everyone that game.info.nplayers has been updated */
-  send_game_info(NULL);
-  send_player_info(pplayer, NULL);
-  notify_conn(NULL, NULL, E_CONNECTION,
-             _("A global observer has been created"));
-
-  return pplayer;
-}
-
-/****************************************************************************
   Called when something is changed; this resets everyone's readiness.
 ****************************************************************************/
 void reset_all_start_commands(void)
Index: server/plrhand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.h,v
retrieving revision 1.85
diff -p -u -r1.85 plrhand.h
--- server/plrhand.h    5 Sep 2005 04:21:55 -0000       1.85
+++ server/plrhand.h    6 Sep 2005 22:01:50 -0000
@@ -70,7 +70,6 @@ void send_player_turn_notifications(stru
 void shuffle_players(void);
 void set_shuffled_players(int *shuffled_players);
 struct player *shuffled_player(int i);
-struct player *create_global_observer(void);
 void reset_all_start_commands(void);
 
 #define shuffled_players_iterate(pplayer)                                   \
Index: server/report.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/report.c,v
retrieving revision 1.71
diff -p -u -r1.71 report.c
--- server/report.c     5 Sep 2005 15:55:47 -0000       1.71
+++ server/report.c     6 Sep 2005 22:01:51 -0000
@@ -97,7 +97,7 @@ static const char *science_to_text(int v
 static const char *mil_service_to_text(int value);
 static const char *pollution_to_text(int value);
 
-#define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p) && !(p)->is_observer)
+#define GOOD_PLAYER(p) ((p)->is_alive && !is_barbarian(p))
 
 /*
  * Describes a row.
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.283
diff -p -u -r1.283 ruleset.c
--- server/ruleset.c    4 Sep 2005 04:31:18 -0000       1.283
+++ server/ruleset.c    6 Sep 2005 22:01:51 -0000
@@ -2127,8 +2127,6 @@ static void load_ruleset_nations(struct 
 
     pl->is_playable = secfile_lookup_bool_default(file, TRUE,
                                                  "%s.is_playable", sec[i]);
-    pl->is_observer = secfile_lookup_bool_default(file, FALSE,
-                                                 "%s.is_observer", sec[i]);
     pl->is_barbarian = secfile_lookup_bool_default(file, FALSE,
                                                  "%s.is_barbarian", sec[i]);
 
@@ -2958,7 +2956,6 @@ void send_ruleset_nations(struct conn_li
     }
     packet.city_style = n->city_style;
     packet.is_playable = n->is_playable;
-    packet.is_observer = n->is_observer;
     packet.is_barbarian = n->is_barbarian;
     memcpy(packet.init_techs, n->init_techs, sizeof(packet.init_techs));
     memcpy(packet.init_buildings, n->init_buildings, 
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.276
diff -p -u -r1.276 savegame.c
--- server/savegame.c   3 Sep 2005 09:58:59 -0000       1.276
+++ server/savegame.c   6 Sep 2005 22:01:52 -0000
@@ -1761,8 +1761,7 @@ static void player_load(struct player *p
   plr->nturns_idle=0;
   plr->is_male=secfile_lookup_bool_default(file, TRUE, "player%d.is_male", 
plrno);
   plr->is_alive=secfile_lookup_bool(file, "player%d.is_alive", plrno);
-  plr->is_observer=secfile_lookup_bool_default(file, FALSE, 
-                                               "player%d.is_observer", plrno);
+  /* "Old" observer players will still be loaded but are considered dead. */
   plr->ai.control = secfile_lookup_bool(file, "player%d.ai.control", plrno);
   for (i = 0; i < MAX_NUM_PLAYERS; i++) {
     plr->ai.love[i]
@@ -2512,7 +2511,6 @@ static void player_save(struct player *p
 
   secfile_insert_bool(file, plr->is_male, "player%d.is_male", plrno);
   secfile_insert_bool(file, plr->is_alive, "player%d.is_alive", plrno);
-  secfile_insert_bool(file, plr->is_observer, "player%d.is_observer", plrno);
   secfile_insert_bool(file, plr->ai.control, "player%d.ai.control", plrno);
   for (i = 0; i < MAX_NUM_PLAYERS; i++) {
     secfile_insert_int(file, plr->ai.love[i],
Index: server/score.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/score.c,v
retrieving revision 1.24
diff -p -u -r1.24 score.c
--- server/score.c      4 Jul 2005 17:48:38 -0000       1.24
+++ server/score.c      6 Sep 2005 22:01:52 -0000
@@ -392,7 +392,7 @@ void calc_civ_score(struct player *pplay
   pplayer->score.literacy = 0;
   pplayer->score.spaceship = 0;
 
-  if (is_barbarian(pplayer) || pplayer->is_observer) {
+  if (is_barbarian(pplayer)) {
     return;
   }
 
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.292
diff -p -u -r1.292 srv_main.c
--- server/srv_main.c   5 Sep 2005 15:55:47 -0000       1.292
+++ server/srv_main.c   6 Sep 2005 22:01:53 -0000
@@ -204,7 +204,7 @@ void srv_init(void)
 **************************************************************************/
 bool is_game_over(void)
 {
-  int barbs = 0, alive = 0, observers = 0;
+  int barbs = 0, alive = 0;
   bool all_allied;
   struct player *victor = NULL;
 
@@ -222,9 +222,6 @@ bool is_game_over(void)
     if (is_barbarian(pplayer)) {
       barbs++;
     }
-    if (pplayer->is_observer) {
-      observers++;
-    }
   } players_iterate_end;
 
   /* count the living */
@@ -238,7 +235,7 @@ bool is_game_over(void)
   } players_iterate_end;
 
   /* the game does not quit if we are playing solo */
-  if (game.info.nplayers == (observers + barbs + 1)
+  if (game.info.nplayers == (barbs + 1)
       && alive >= 1) {
     return FALSE;
   }
@@ -1336,8 +1333,7 @@ void handle_player_ready(struct player *
 ****************************************************************************/
 void aifill(int amount)
 {
-  int observers = 0, remove;
-  int filled = 0;
+  int remove, filled = 0;
 
   if (server_state != PRE_GAME_STATE || !game.info.is_new_game) {
     return;
@@ -1350,18 +1346,7 @@ void aifill(int amount)
 
   amount = MIN(amount, game.info.max_players);
 
-  /* we don't want aifill to count global observers unless 
-   * aifill = MAX_NUM_PLAYERS */
-  players_iterate(pplayer) {
-    if (pplayer->is_observer) {
-      observers++;
-    }
-  } players_iterate_end;
-  if (amount == game.info.max_players) {
-    observers = 0;
-  }
-
-  while (game.info.nplayers < amount + observers) {
+  while (game.info.nplayers < amount) {
     const int old_nplayers = game.info.nplayers;
     struct player *pplayer = get_player(old_nplayers);
     char player_name[ARRAY_SIZE(pplayer->name)];
@@ -1394,11 +1379,10 @@ void aifill(int amount)
   }
 
   remove = game.info.nplayers - 1;
-  while (game.info.nplayers > amount + observers && remove >= 0) {
+  while (game.info.nplayers > amount && remove >= 0) {
     struct player *pplayer = get_player(remove);
 
-    if (!pplayer->is_observer && !pplayer->is_connected
-       && !pplayer->was_created) {
+    if (!pplayer->is_connected && !pplayer->was_created) {
       server_remove_player(pplayer);
     }
     remove--;
@@ -1863,13 +1847,6 @@ static void srv_loop(void)
   
   if(game.info.is_new_game) {
     init_new_game();
-
-    /* give global observers the entire map */
-    players_iterate(pplayer) {
-      if (pplayer->is_observer) {
-        map_know_and_see_all(pplayer);
-      }
-    } players_iterate_end;
   }
 
   send_game_state(game.est_connections, CLIENT_GAME_RUNNING_STATE);
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.436
diff -p -u -r1.436 stdinhand.c
--- server/stdinhand.c  5 Sep 2005 15:55:47 -0000       1.436
+++ server/stdinhand.c  6 Sep 2005 22:01:57 -0000
@@ -142,7 +142,8 @@ static PlayerNameStatus test_player_name
       return PNameTooLong;
   } else if (mystrcasecmp(name, ANON_PLAYER_NAME) == 0) {
       return PNameIllegal;
-  } else if (mystrcasecmp(name, OBSERVER_NAME) == 0) {
+  } else if (mystrcasecmp(name, "Observer") == 0) {
+    /* "Observer" used to be illegal and we keep it that way for now. */
       return PNameIllegal;
   }
 
@@ -833,23 +834,6 @@ static bool toggle_ai_player(struct conn
   return TRUE;
 }
 
-/****************************************************************************
-  Return the number of non-observer players.  game.info.nplayers includes
-  observers so in some places this function should be called instead.
-****************************************************************************/
-static int get_num_nonobserver_players(void)
-{
-  int nplayers = 0;
-
-  players_iterate(pplayer) {
-    if (!pplayer->is_observer) {
-      nplayers++;
-    }
-  } players_iterate_end;
-
-  return nplayers;
-}
-
 /**************************************************************************
 ...
 **************************************************************************/
@@ -867,8 +851,7 @@ static bool create_ai_player(struct conn
 
   /* game.info.max_players is a limit on the number of non-observer players.
    * MAX_NUM_PLAYERS is a limit on all players. */
-  if (get_num_nonobserver_players() >= game.info.max_players
-      || game.info.nplayers >= MAX_NUM_PLAYERS) {
+  if (game.info.nplayers >= game.info.max_players) {
     cmd_reply(CMD_CREATE, caller, C_FAIL,
              _("Can't add more players, server is full."));
     return FALSE;
@@ -2110,7 +2093,7 @@ static bool vote_command(struct connecti
   if (caller == NULL || caller->player == NULL) {
     cmd_reply(CMD_VOTE, caller, C_FAIL, _("This command is client only."));
     return FALSE;
-  } else if (caller->player->is_observer || caller->observer) {
+  } else if (caller->observer) {
     cmd_reply(CMD_VOTE, caller, C_FAIL, _("Observers cannot vote."));
     return FALSE;
   } else if (server_state != RUN_GAME_STATE) {
@@ -2544,7 +2527,8 @@ static bool is_allowed_to_take(struct pl
 {
   const char *allow;
 
-  if (pplayer->is_observer) {
+  if (!pplayer) {
+    /* Observer */
     if (!(allow = strchr(game.allow_take, (game.info.is_new_game ? 'O' : 
'o')))) {
       if (will_obs) {
         mystrlcpy(msg, _("Sorry, one can't observe globally in this game."),
@@ -2688,11 +2672,6 @@ static bool observe_command(struct conne
   }
 
   /* if we have no pplayer, it means that we want to be a global observer */
-  if (!pplayer) {
-    if (!(pplayer = create_global_observer())) {
-      goto end; /* couldn't create an observer */ 
-    }
-  }
 
   /******** PART II: do the observing ********/
 
@@ -2703,8 +2682,11 @@ static bool observe_command(struct conne
   }
 
   /* observing your own player (during pregame) makes no sense. */
-  if (pconn->player == pplayer && !pconn->observer
-      && is_newgame && !pplayer->was_created) {
+  if (pplayer
+      && pconn->player == pplayer
+      && !pconn->observer
+      && is_newgame
+      && !pplayer->was_created) {
     cmd_reply(CMD_OBSERVE, caller, C_FAIL, 
               _("%s already controls %s. Using 'observe' would remove %s"),
               pconn->username, pplayer->name, pplayer->name);
@@ -2713,9 +2695,15 @@ static bool observe_command(struct conne
 
   /* attempting to observe a player you're already observing should fail. */
   if (pconn->player == pplayer && pconn->observer) {
-    cmd_reply(CMD_OBSERVE, caller, C_FAIL,
-              _("%s is already observing %s."),  
-              pconn->username, pplayer->name);
+    if (pplayer) {
+      cmd_reply(CMD_OBSERVE, caller, C_FAIL,
+               _("%s is already observing %s."),  
+               pconn->username, pplayer->name);
+    } else {
+      cmd_reply(CMD_OBSERVE, caller, C_FAIL,
+               _("%s is already observing."),  
+               pconn->username);
+    }
     goto end;
   }
 
@@ -2729,13 +2717,17 @@ static bool observe_command(struct conne
   if (pconn->player) {
     char name[MAX_LEN_NAME];
 
-    /* if a pconn->player is removed, we'll lose pplayer */
-    sz_strlcpy(name, pplayer->name);
-  
+    if (pplayer) {
+      /* if a pconn->player is removed, we'll lose pplayer */
+      sz_strlcpy(name, pplayer->name);
+    }
+
     detach_command(NULL, pconn->username, FALSE);
 
-    /* find pplayer again, the pointer might have been changed */
-    pplayer = find_player_by_name(name);
+    if (pplayer) {
+      /* find pplayer again, the pointer might have been changed */
+      pplayer = find_player_by_name(name);
+    }
   } 
 
   /* we don't want the connection's username on another player */
@@ -2747,7 +2739,11 @@ static bool observe_command(struct conne
 
   /* attach pconn to new player as an observer */
   pconn->observer = TRUE; /* do this before attach! */
-  attach_connection_to_player(pconn, pplayer);
+  if (pplayer) {
+    attach_connection_to_player(pconn, pplayer);
+  } else {
+    unattach_connection_from_player(pconn);
+  }
   send_conn_info(pconn->self, game.est_connections);
 
   if (server_state == RUN_GAME_STATE) {
@@ -2760,8 +2756,13 @@ static bool observe_command(struct conne
     dsend_packet_start_phase(pconn, game.info.phase);
   }
 
-  cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes %s"),
-            pconn->username, pplayer->name);
+  if (pplayer) {
+    cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes %s"),
+             pconn->username, pplayer->name);
+  } else {
+    cmd_reply(CMD_OBSERVE, caller, C_OK, _("%s now observes"),
+             pconn->username);
+  }
 
   end:;
   /* free our args */
@@ -2839,13 +2840,6 @@ static bool take_command(struct connecti
     goto end;
   }
 
-  /* you may not take over a global observer */
-  if (pplayer->is_observer) {
-    cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s cannot be taken."),
-              pplayer->name);
-    goto end;
-  } 
-
   /* taking your own player makes no sense. */
   if (pconn->player == pplayer && !pconn->observer) {
     cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s already controls %s"),
@@ -2960,7 +2954,7 @@ static bool detach_command(struct connec
   struct connection *pconn = NULL;
   struct player *pplayer = NULL;
   bool is_newgame = server_state == PRE_GAME_STATE && game.info.is_new_game;
-  bool one_obs_among_many = FALSE, res = FALSE;
+  bool res = FALSE;
 
   sz_strlcpy(buf, str);
   ntokens = get_tokens(buf, arg, 1, TOKEN_DELIMITERS);
@@ -3000,12 +2994,6 @@ static bool detach_command(struct connec
     goto end;
   }
 
-  /* a special case for global observers: we don't want to remove the
-   * observer player in pregame if someone else is also observing it */
-  if (pplayer->is_observer && conn_list_size(pplayer->connections) > 1) {
-    one_obs_among_many = TRUE;
-  }
-
   res = TRUE;
   if (check) {
     goto end;
@@ -3030,8 +3018,7 @@ static bool detach_command(struct connec
   /* only remove the player if the game is new and in pregame, 
    * the player wasn't /created, and no one is controlling it 
    * and we were observing but no one else was... */
-  if (!pplayer->is_connected && !pplayer->was_created && is_newgame
-      && !one_obs_among_many) {
+  if (!pplayer->is_connected && !pplayer->was_created && is_newgame) {
     /* detach any observers */
     conn_list_iterate(pplayer->connections, aconn) {
       if (aconn->observer) {
@@ -3338,7 +3325,6 @@ bool handle_stdin_input(struct connectio
   if (caller 
       && caller->player
       && !check
-      && !caller->player->is_observer
       && caller->access_level == ALLOW_INFO
       && commands[cmd].level == ALLOW_CTRL) {
     int idx = caller->player->player_no;
@@ -3571,10 +3557,10 @@ static bool start_command(struct connect
        game.info.max_players = map.num_start_positions;
       }
 
-      if (get_num_nonobserver_players() > game.info.max_players) {
+      if (game.info.nplayers > game.info.max_players) {
        /* Because of the way player ids are renumbered during
           server_remove_player() this is correct */
-        while (get_num_nonobserver_players() > game.info.max_players) {
+        while (game.info.nplayers > game.info.max_players) {
          /* This may erronously remove observer players sometimes.  This
           * is a bug but non-fatal. */
          server_remove_player(get_player(game.info.max_players));
@@ -3589,7 +3575,7 @@ static bool start_command(struct connect
     }
 
     /* check min_players */
-    if (get_num_nonobserver_players() < game.info.min_players) {
+    if (game.info.nplayers < game.info.min_players) {
       cmd_reply(CMD_START_GAME, caller, C_FAIL,
                _("Not enough players, game will not start."));
       return FALSE;

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