Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2004:
[Freeciv-Dev] Re: (PR#7241) Wish List: observer mode
Home

[Freeciv-Dev] Re: (PR#7241) Wish List: observer mode

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: ue80@xxxxxxxxxxxxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#7241) Wish List: observer mode
From: "Mike Kaufman" <kaufman@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 28 Aug 2004 15:41:28 -0700
Reply-to: rt@xxxxxxxxxxx

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

attached is a patch to implement a global observer mode.

I thought long and hard about it, but it seems the best way to implement
the mode is through the dead player which was done in the /dead.

I've added a couple of improvements to the patch. First, use

/obs connection

to attach to a global observer. Second, you can create global observers in
pregame. Also, I've created a unique nation (with a white flag) for
observers.

Hopefully all the /take /obs /detach, etc logic is ok, I _think_ I debugged
it thoroughly, but there could be a corner case I missed.

In my testing (before I fixed everything I found that needed to be fixed) I
was getting some core dumps when I quit out of the server. Hopefully my
fixes cured all this, but look out for them.

-mike

diff -Nur -Xcvs/diff_ignore snap/common/nation.h snap-obs/common/nation.h
--- snap/common/nation.h        2004-07-24 12:39:02.000000000 -0500
+++ snap-obs/common/nation.h    2004-08-28 11:38:57.000000000 -0500
@@ -21,6 +21,8 @@
 /* Changing this value will break network compatibility. */
 #define NO_NATION_SELECTED (Nation_Type_id)(-1)
 
+#define OBSERVER_NATION (game.nation_count - 2)
+
 /* 
  * Purpose of this constant is to catch invalid ruleset and network
  * data and to allow static allocation of the nation_info packet.
diff -Nur -Xcvs/diff_ignore snap/common/player.c snap-obs/common/player.c
--- snap/common/player.c        2004-08-28 10:38:53.000000000 -0500
+++ snap-obs/common/player.c    2004-08-28 11:48:22.000000000 -0500
@@ -101,6 +101,7 @@
   conn_list_init(&plr->connections);
   plr->current_conn = NULL;
   plr->is_connected = FALSE;
+  plr->is_observer = FALSE;
   plr->was_created = FALSE;
   plr->is_alive=TRUE;
   plr->is_dying = FALSE;
diff -Nur -Xcvs/diff_ignore snap/common/player.h snap-obs/common/player.h
--- snap/common/player.h        2004-08-28 10:38:53.000000000 -0500
+++ snap-obs/common/player.h    2004-08-28 16:51:56.533658904 -0500
@@ -30,6 +30,7 @@
 
 #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
@@ -186,6 +187,7 @@
   bool turn_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 got_tech; /* set once the player is fully dead */
 
diff -Nur -Xcvs/diff_ignore snap/data/civ1/nations.ruleset 
snap-obs/data/civ1/nations.ruleset
--- snap/data/civ1/nations.ruleset      2004-02-22 11:12:03.000000000 -0600
+++ snap-obs/data/civ1/nations.ruleset  2004-08-28 14:02:54.019104395 -0500
@@ -62,6 +62,7 @@
 *include "nation/mongol.ruleset"
 
 ;
-; barbarians MUST go last
+; observer and barbarians MUST go last in THIS order
 ;
+*include "nation/observer.ruleset"
 *include "nation/barbarian.ruleset"
diff -Nur -Xcvs/diff_ignore snap/data/default/nations.ruleset 
snap-obs/data/default/nations.ruleset
--- snap/data/default/nations.ruleset   2004-06-26 17:14:01.000000000 -0500
+++ snap-obs/data/default/nations.ruleset       2004-08-28 14:02:01.720584942 
-0500
@@ -103,6 +103,7 @@
 *include "nation/afghani.ruleset"
 
 ;
-; barbarians MUST go last
+; observer and barbarians MUST go last in THIS order
 ;
+*include "nation/observer.ruleset"
 *include "nation/barbarian.ruleset"
diff -Nur -Xcvs/diff_ignore snap/data/flags/Makefile.am 
snap-obs/data/flags/Makefile.am
--- snap/data/flags/Makefile.am 2004-06-25 20:37:21.000000000 -0500
+++ snap-obs/data/flags/Makefile.am     2004-08-28 11:09:59.000000000 -0500
@@ -58,6 +58,7 @@
                nato.png                \
                netherlands.png         \
                norway.png              \
+               observer.png            \
                olympic.png             \
                pakistan.png            \
                peru.png                \
diff -Nur -Xcvs/diff_ignore snap/data/misc/flags.spec 
snap-obs/data/misc/flags.spec
--- snap/data/misc/flags.spec   2004-07-17 10:33:42.000000000 -0500
+++ snap-obs/data/misc/flags.spec       2004-08-28 11:27:34.000000000 -0500
@@ -76,6 +76,7 @@
                "f.nato", "flags/nato"
                "f.netherlands", "flags/netherlands"
                "f.norway", "flags/norway"
+               "f.observer", "flags/observer"
                "f.olympic", "flags/olympic"
                "f.pakistan", "flags/pakistan"
                "f.peru", "flags/peru"
diff -Nur -Xcvs/diff_ignore snap/data/nation/Makefile.am 
snap-obs/data/nation/Makefile.am
--- snap/data/nation/Makefile.am        2004-08-28 10:42:46.000000000 -0500
+++ snap-obs/data/nation/Makefile.am    2004-08-28 11:24:19.000000000 -0500
@@ -49,6 +49,7 @@
                lithuanian.ruleset \
                mongol.ruleset \
                mordor.ruleset \
+               observer.ruleset \
                persian.ruleset \
                polish.ruleset \
                portuguese.ruleset \
diff -Nur -Xcvs/diff_ignore snap/data/nation/observer.ruleset 
snap-obs/data/nation/observer.ruleset
--- snap/data/nation/observer.ruleset   1969-12-31 18:00:00.000000000 -0600
+++ snap-obs/data/nation/observer.ruleset       2004-08-28 16:30:21.342413569 
-0500
@@ -0,0 +1,20 @@
+[nation_observer]
+
+name=_("Observer")
+plural=_("?plural:Observers")
+leader="None"
+leader_sex="Male"
+flag="f.observer"
+flag_alt = "-"
+city_style = "Classical"
+
+init_techs=""
+init_buildings=""
+
+tech_goals = ""
+wonder = ""
+government = "Anarchy"
+
+cities = "Nowhere"
+
+; nothing more needed for observer
diff -Nur -Xcvs/diff_ignore snap/po/POTFILES.in snap-obs/po/POTFILES.in
--- snap/po/POTFILES.in 2004-07-17 10:33:49.000000000 -0500
+++ snap-obs/po/POTFILES.in     2004-08-28 11:24:03.000000000 -0500
@@ -270,6 +270,7 @@
 data/nation/lithuanian.ruleset
 data/nation/mongol.ruleset
 data/nation/mordor.ruleset
+data/nation/observer.ruleset
 data/nation/persian.ruleset
 data/nation/polish.ruleset
 data/nation/portuguese.ruleset
diff -Nur -Xcvs/diff_ignore snap/server/gamehand.c snap-obs/server/gamehand.c
--- snap/server/gamehand.c      2004-07-24 12:39:08.000000000 -0500
+++ snap-obs/server/gamehand.c  2004-08-28 13:49:42.045029132 -0500
@@ -183,6 +183,11 @@
     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.x, pos.y, pplayer, game.start_units[0]);
   } players_iterate_end;
@@ -193,6 +198,11 @@
     struct start_position p
       = map.start_positions[start_pos[pplayer->player_no]];
 
+    /* don't give any units to observer */
+    if (pplayer->is_observer) {
+      continue;
+    }
+
     for (i = 1; i < strlen(game.start_units); i++) {
       do {
        x = p.x + myrand(2 * game.dispersion + 1) - game.dispersion;
diff -Nur -Xcvs/diff_ignore snap/server/ruleset.c snap-obs/server/ruleset.c
--- snap/server/ruleset.c       2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/ruleset.c   2004-08-28 11:06:59.000000000 -0500
@@ -2052,7 +2052,7 @@
   (void) section_file_lookup(file, "datafile.description");    /* unused */
 
   sec = secfile_get_secnames_prefix(file, "nation", &game.nation_count);
-  game.playable_nation_count = game.nation_count - 1;
+  game.playable_nation_count = game.nation_count - 2;
   freelog(LOG_VERBOSE, "There are %d nations defined", 
game.playable_nation_count);
 
   if (game.playable_nation_count < 0) {
diff -Nur -Xcvs/diff_ignore snap/server/srv_main.c snap-obs/server/srv_main.c
--- snap/server/srv_main.c      2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/srv_main.c  2004-08-28 15:07:05.399525586 -0500
@@ -193,7 +193,7 @@
 **************************************************************************/
 static bool is_game_over(void)
 {
-  int barbs = 0, alive = 0;
+  int barbs = 0, alive = 0, observers = 0;
   bool all_allied;
   struct player *victor = NULL;
 
@@ -205,17 +205,20 @@
     return TRUE;
   }
 
-  /* count barbarians */
+  /* count barbarians and observers */
   players_iterate(pplayer) {
     if (is_barbarian(pplayer)) {
       barbs++;
     }
+    if (pplayer->is_observer) {
+      observers++;
+    }
   } players_iterate_end;
 
   /* the game does not quit if we are playing solo */
-  if (game.nplayers == (barbs + 1)) {
+  if (game.nplayers == (observers + barbs + 1)) {
     return FALSE;
-  }
+  } 
 
   /* count the living */
   players_iterate(pplayer) {
@@ -1271,7 +1274,15 @@
              game.max_players);
   }
 
-  for(;game.nplayers < game.aifill;) {
+  /* we don't want aifill to count global observers... */
+  i = 0;
+  players_iterate(pplayer) {
+    if (pplayer->is_observer) {
+      i++;
+    }
+  } players_iterate_end;
+
+  for(;game.nplayers < game.aifill + i;) {
     nation = select_random_nation(common_class);
     assert(nation != NO_NATION_SELECTED);
     mark_nation_as_used(nation);
@@ -1635,7 +1646,9 @@
    */
   server_state = RUN_GAME_STATE;
   players_iterate(pplayer) {
-    if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) {
+    if (pplayer->is_observer) {
+      pplayer->nation = OBSERVER_NATION;
+    } else if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) {
       send_select_nation(pplayer);
       server_state = SELECT_RACES_STATE;
     }
@@ -1726,6 +1739,7 @@
     if(map.num_start_positions == 0) {
       create_start_positions();
     }
+
   }
 
   /* start positions are created, now we can do this safely */
@@ -1771,6 +1785,13 @@
   
   if(game.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.game_connections, CLIENT_GAME_RUNNING_STATE);
diff -Nur -Xcvs/diff_ignore snap/server/stdinhand.c snap-obs/server/stdinhand.c
--- snap/server/stdinhand.c     2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/stdinhand.c 2004-08-28 17:33:29.714893901 -0500
@@ -51,6 +51,7 @@
 #include "gamehand.h"
 #include "gamelog.h"
 #include "mapgen.h"
+#include "maphand.h"
 #include "meta.h"
 #include "plrhand.h"
 #include "report.h"
@@ -1083,7 +1084,8 @@
 typedef enum {
     PNameOk,
     PNameEmpty,
-    PNameTooLong
+    PNameTooLong,
+    PNameIllegal
 } PlayerNameStatus;
 
 /**************************************************************************
@@ -1097,6 +1099,8 @@
       return PNameEmpty;
   } else if (len > MAX_LEN_NAME-1) {
       return PNameTooLong;
+  } else if (strcmp(name, OBSERVER_NAME) == 0 ) {
+      return PNameIllegal;
   }
 
   return PNameOk;
@@ -2149,6 +2153,13 @@
     return FALSE;
   }
 
+  if (PNameStatus == PNameIllegal)
+  {
+    cmd_reply(CMD_CREATE, caller, C_SYNTAX, _("That name is not allowed."));
+    return FALSE;
+  }       
+
+
   if ((pplayer=find_player_by_name(arg))) {
     cmd_reply(CMD_CREATE, caller, C_BOUNCE,
              _("A player already exists by that name."));
@@ -3842,16 +3853,6 @@
     goto end;
   }
 
-#define NO_GLOBAL_OBS /* remove this construction when global obs is reality */
-
-#ifdef NO_GLOBAL_OBS
-  if ((caller && ntokens == 0) || (!caller && ntokens == 1)) {
-    cmd_reply(CMD_OBSERVE, caller, C_SYNTAX,
-              _("Usage: observe [connection-name [player-name]]"));
-    goto end;
-  }
-#endif
-
   /* match connection if we're console, match a player if we're not */
   if (ntokens == 1) {
     if (!caller && !(pconn = find_conn_by_user_prefix(arg[0], &result))) {
@@ -3881,9 +3882,47 @@
     pconn = caller;
   }
 
-#ifndef NO_GLOBAL_OBS
-  /* global observing needs some code here! */ 
-#endif
+  /* if we have no pplayer, it means that we want to be a global observer */
+  if (!pplayer) {
+    /* check if a global  observer has already been created */
+    players_iterate(aplayer) {
+      if (aplayer->is_observer) {
+        pplayer = aplayer;
+        break;
+      }
+    } players_iterate_end;
+
+    /* we need to create a new player */
+    if (!pplayer) {
+      if (game.nplayers >= MAX_NUM_PLAYERS) {
+        notify_player(NULL, _("Game: A global observer cannot be created: too "
+                              "many regular players."));
+        goto end;
+      }
+
+      pplayer = &game.players[game.nplayers];
+      server_player_init(pplayer, 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;
+      pplayer->turn_done = TRUE;
+      pplayer->embassy = 0;   /* no embassys */
+      pplayer->is_alive = FALSE;
+      pplayer->was_created = FALSE;
+
+      if (server_state == RUN_GAME_STATE) {
+        pplayer->nation = OBSERVER_NATION;
+        init_tech(pplayer, 0);
+        map_know_and_see_all(pplayer);
+      }
+
+      game.nplayers++;
+      notify_player(NULL, _("Game: A global observer has been created"));
+    }
+  }
 
   /******** PART II: do the observing ********/
 
@@ -4032,6 +4071,13 @@
     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"),
@@ -4131,7 +4177,7 @@
   struct player *pplayer = NULL;
   bool is_newgame = (server_state == PRE_GAME_STATE || 
                      server_state == SELECT_RACES_STATE) && game.is_new_game;
-  bool res = FALSE;
+  bool one_obs_among_many = FALSE, res = FALSE;
 
   sz_strlcpy(buf, str);
   ntokens = get_tokens(buf, arg, 1, TOKEN_DELIMITERS);
@@ -4171,6 +4217,18 @@
     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 */
+  i = 0;
+  conn_list_iterate(pplayer->connections, aconn) {
+    if (aconn->observer) {
+      i++;
+    }
+  } conn_list_iterate_end;
+  if (i > 1 && pconn->observer) {
+    one_obs_among_many = TRUE;
+  }
+
   res = TRUE;
   if (check) {
     goto end;
@@ -4187,8 +4245,10 @@
             _("%s detaching from %s"), pconn->username, pplayer->name);
 
   /* only remove the player if the game is new and in pregame, 
-   * the player wasn't /created, and no one is controlling it */
-  if (!pplayer->is_connected && !pplayer->was_created && is_newgame) {
+   * 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) {
     /* detach any observers */
     conn_list_iterate(pplayer->connections, aconn) {
       if (aconn->observer) {
@@ -4200,6 +4260,7 @@
     /* actually do the removal */
     game_remove_player(pplayer);
     game_renumber_players(pplayer->player_no);
+    player_init(&game.players[game.nplayers]);
   }
 
   if (!pplayer->is_connected) {

PNG image


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