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

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

[Top] [All Lists]

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

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

The current observer system has several drawbacks, which are insolvable.

- Observers have to be put into savegames.

- Observers are included in all lists of players, except where they are 
specifically excepted.

- There are problems with maxplayers.  Observers count toward the total 
of MAX_NUM_PLAYERS but not maxplayers.  This may mean that an observer 
isn't allowed to connect, even if you leave a place open for one at the 
start of the game, once there are already 32 players in the game.  It 
may also mean civil war isn't allowed when it otherwise would be (but 
this could happen anyway of course).

- This is especially problematic in the new civ-editor model.  The new 
civ-editor needs to be able to handle data for all players in the client 
(seeing internals of all cities, units, players, tiles, etc.).  In 
particular, with the current observer system any scenario created with 
the new civ editor would end up with an observer in its first player spot.

This patch solves it by implementing the original observer design: 
observers are connections with pconn->observer set and pconn->player as 
NULL.  This makes the server code vastly simpler since all 
observer-player code is simply removed.  In the client however a lot of 
extra code must be added.  Since game.player_ptr may be NULL throughout 
the client we have to be very careful before using it.  Basically every 
player_ptr user must check if it is NULL before using it (there are 
about 250 users in the core client code plus about 150 in each GUI). 
It's worth noting that in most cases the result of "faking" an observer 
player simply give garbage in this case anyway: the science dialog is 
useless, the nation is listed as "Observer", etc.  Future cleanups 
should allow repodlgs for observers to look at _any_ player.

This patch isn't ready to be committed.  It needs further testing and 
review.  In particular every player_ptr user still needs to be checked 
(so far only the obvious ones have been fixed).

-jason

? common/stCeuPjp
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  5 Sep 2005 20:32:20 -0000
@@ -724,8 +724,8 @@ 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()
+         && could_meet_with_player(game.player_ptr, pplayer));
 }
 
 /**************************************************************************
@@ -734,7 +734,8 @@ 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()
+         ||could_intel_with_player(game.player_ptr, pplayer));
 }
 
 /**************************************************************************
@@ -744,7 +745,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     5 Sep 2005 20:32:20 -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    5 Sep 2005 20:32:20 -0000
@@ -193,7 +193,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 +221,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 +376,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 +406,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);
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    5 Sep 2005 20:32:21 -0000
@@ -227,7 +227,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 +261,7 @@ 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());
+  assert(game.player_ptr && can_client_change_view());
 
   set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
   if (!can_client_change_view()) {
@@ -315,7 +315,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;
   }
@@ -1479,11 +1480,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);
   }
 
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     5 Sep 2005 20:32:21 -0000
@@ -1253,7 +1253,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);
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  5 Sep 2005 20:32:21 -0000
@@ -75,8 +75,9 @@ 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->ai.control) {
     popup_meswin_dialog(FALSE);
     change = FALSE;
     return;
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    5 Sep 2005 20:32:21 -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   5 Sep 2005 20:32:22 -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,8 +597,8 @@ 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->ai.control) {
     update_menus();
     if (!city_dialog_is_open(pcity)) {
       popup_city_dialog(pcity);
@@ -776,8 +777,7 @@ void handle_new_year(int year, int turn)
 
   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 +908,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 +992,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
@@ -1112,7 +1108,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 +1128,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 +1143,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 +1233,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();
@@ -1394,8 +1394,8 @@ 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()
+      && government != game.player_ptr->government) {
     dsend_packet_player_change_government(&aconnection, government->index);
   }
 }
@@ -1424,7 +1424,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 +1500,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 +1905,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 +2359,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 +2470,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 +2485,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);
     }
   }
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      5 Sep 2005 20:32:22 -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    5 Sep 2005 20:32:22 -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    5 Sep 2005 20:32:22 -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/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        5 Sep 2005 20:32:22 -0000
@@ -1099,8 +1099,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;
 
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       5 Sep 2005 20:32:22 -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/helpdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/helpdlg.c,v
retrieving revision 1.62
diff -p -u -r1.62 helpdlg.c
--- client/gui-gtk-2.0/helpdlg.c        18 Aug 2005 06:44:27 -0000      1.62
+++ client/gui-gtk-2.0/helpdlg.c        5 Sep 2005 20:32:23 -0000
@@ -208,19 +208,22 @@ static void create_tech_tree(int tech, i
     return;
   }
 
-  bg = COLOR_REQTREE_BACKGROUND;
-  switch (get_invention(game.player_ptr, tech)) {
-  case TECH_UNKNOWN:
-    bg = COLOR_REQTREE_UNREACHABLE;
-    break;
-  case TECH_KNOWN:
-    bg = COLOR_REQTREE_KNOWN;
-    break;
-  case TECH_REACHABLE:
-    bg = COLOR_REQTREE_REACHABLE;
-    break;
+  bg = COLOR_REQTREE_KNOWN;
+  turns_to_tech = 0;
+  if (game.player_ptr) {
+    switch (get_invention(game.player_ptr, tech)) {
+    case TECH_UNKNOWN:
+      bg = COLOR_REQTREE_UNREACHABLE;
+      break;
+    case TECH_KNOWN:
+      bg = COLOR_REQTREE_KNOWN;
+      break;
+    case TECH_REACHABLE:
+      bg = COLOR_REQTREE_REACHABLE;
+      break;
+    }
+    turns_to_tech = num_unknown_techs_for_goal(game.player_ptr, tech);
   }
-  turns_to_tech = num_unknown_techs_for_goal(game.player_ptr, tech);
 
   /* l is the original in the tree. */
   original = !help_advances[tech];
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   5 Sep 2005 20:32:23 -0000
@@ -1246,7 +1246,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 +1386,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/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 5 Sep 2005 20:32:23 -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:
-      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);
+    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);
     }
 
     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       5 Sep 2005 20:32:23 -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 (game.player_ptr
+      && 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 && game.player_ptr) {
     /* 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 || is_report_dialogs_frozen()) {
     return;
   }
 
@@ -1087,9 +1077,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
@@ -1189,10 +1182,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: 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       5 Sep 2005 20:32:23 -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     5 Sep 2005 20:32:24 -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     5 Sep 2005 20:32:24 -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  5 Sep 2005 20:32:24 -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     5 Sep 2005 20:32:24 -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;
@@ -763,6 +762,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     5 Sep 2005 20:32:24 -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       5 Sep 2005 20:32:25 -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 return 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,
@@ -514,10 +526,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 +543,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 +607,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 +627,27 @@ const char *get_tech_name(const struct p
     /* TRANS: "None" tech */
     return _("None");
   case A_FUTURE:
-    research = get_player_research(pplayer);
-
-    /* pplayer->future_tech == 0 means "Future Tech. 1". */
-    for (i = future.size; i <= research->future_tech; i++) {
-      char *ptr = NULL;
+    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;
 
-      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   5 Sep 2005 20:32:26 -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        5 Sep 2005 20:32:26 -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     5 Sep 2005 20:32:26 -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   5 Sep 2005 20:32:26 -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    5 Sep 2005 20:32:26 -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    5 Sep 2005 20:32:26 -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     5 Sep 2005 20:32:27 -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    5 Sep 2005 20:32:27 -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   5 Sep 2005 20:32:28 -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      5 Sep 2005 20:32:28 -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   5 Sep 2005 20:32:29 -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  5 Sep 2005 20:32:29 -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]
  • [Freeciv-Dev] (PR#13878) redesign observers, Jason Short <=