Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2005:
[Freeciv-Dev] (PR#9172) RFC: Choose nations in pregame
Home

[Freeciv-Dev] (PR#9172) RFC: Choose nations in pregame

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To:
Subject: [Freeciv-Dev] (PR#9172) RFC: Choose nations in pregame
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 2 May 2005 18:47:02 -0700
Reply-to: bugs@xxxxxxxxxxx

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

This patch implements pregame nations.

- The select-races game state is removed.
- The player may select a nation in pregame.
- All this info is sent to the client.
- Once the game starts random nations are assigned to any players who
haven't chosen nations yet.

All in all it's quite nice, and *could* be ready for committing. 
However there are some shortcomings:

- When changing rulesets all existing nation selections must be reset. 
This is done but it's a hack.
- When loading a savegame some existing nations selections must be
changed.  This wasn't done before (setting up nations_used after a
/load) and it's not done now.  However I don't think it's a fatal error.
- The client has a very useless UI when loading a scenario.  This was
already the case, of course.
- Maybe some other corner cases don't work properly.

-jason

Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.221
diff -u -r1.221 civclient.c
--- client/civclient.c  28 Apr 2005 17:19:52 -0000      1.221
+++ client/civclient.c  3 May 2005 01:43:33 -0000
@@ -502,8 +502,7 @@
        select dialog.)
     */
     if (client_state==CLIENT_PRE_GAME_STATE
-       && (newstate==CLIENT_SELECT_RACE_STATE
-           || newstate==CLIENT_GAME_RUNNING_STATE)) {
+       && newstate == CLIENT_GAME_RUNNING_STATE) {
       translate_data_names();
       audio_stop();            /* stop intro sound loop */
     }
Index: client/packhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v
retrieving revision 1.501
diff -u -r1.501 packhand.c
--- client/packhand.c   2 May 2005 15:42:52 -0000       1.501
+++ client/packhand.c   3 May 2005 01:43:34 -0000
@@ -341,9 +341,8 @@
 {
   bool changed = (get_client_state() != value);
 
-  if (get_client_state() == CLIENT_SELECT_RACE_STATE
-      && value == CLIENT_GAME_RUNNING_STATE
-      && game.player_ptr->nation == NO_NATION_SELECTED) {
+  if (get_client_state() == CLIENT_PRE_GAME_STATE
+      && value == CLIENT_GAME_RUNNING_STATE) {
     popdown_races_dialog();
   }
   
@@ -1385,7 +1384,7 @@
      game.great_wonders[i]=pinfo->great_wonders[i];
   }
 
-  if (get_client_state() == CLIENT_SELECT_RACE_STATE) {
+  if (get_client_state() == CLIENT_PRE_GAME_STATE) {
     popdown_races_dialog();
   }
   game.techpenalty=pinfo->techpenalty;
@@ -2033,31 +2032,23 @@
 }
 
 /**************************************************************************
-...
+  Mark a nation as unavailable or available, after we've entered the
+  select-race state.
 **************************************************************************/
-void handle_nation_select_ok(void)
+void handle_nation_available(Nation_type_id nation_no,
+                            bool is_unavailable, bool is_used)
 {
-  if (get_client_state() == CLIENT_SELECT_RACE_STATE) {
-    set_client_state(CLIENT_WAITING_FOR_GAME_START_STATE);
-    popdown_races_dialog();
-  } else {
-    freelog(LOG_ERROR,
-           "got a select nation packet in an incompatible state");
-  }
-}
+  if (get_client_state() == CLIENT_PRE_GAME_STATE
+      && nation_no >= 0 && nation_no < game.playable_nation_count) {
+    struct nation_type *nation = get_nation_by_idx(nation_no);
+    const bool changed = (nation->is_unavailable != is_unavailable
+                         || nation->is_used != is_used);
 
-static bool *nations_used;
+    nation->is_unavailable = is_unavailable;
+    nation->is_used = is_used;
 
-/**************************************************************************
-  Mark a nation as unavailable, after we've entered the select-race state.
-**************************************************************************/
-void handle_nation_unavailable(Nation_type_id nation)
-{
-  if (get_client_state() == CLIENT_SELECT_RACE_STATE
-      && nation >= 0 && nation < game.playable_nation_count) {
-    if (!nations_used[nation]) {
-      nations_used[nation] = TRUE;
-      races_toggles_set_sensitive(nations_used);
+    if (changed) {
+      races_toggles_set_sensitive();
     }
   } else {
     freelog(LOG_ERROR,
@@ -2066,31 +2057,6 @@
 }
 
 /**************************************************************************
-  Enter the select races state.
-**************************************************************************/
-void handle_select_races(void)
-{
-  if (get_client_state() == CLIENT_PRE_GAME_STATE) {
-    /* First set the state. */
-    set_client_state(CLIENT_SELECT_RACE_STATE);
-
-    /* Then clear the nations used.  They are filled by a
-     * PACKET_NATION_UNAVAILABLE packet that follows. */
-    nations_used = fc_realloc(nations_used,
-                             game.playable_nation_count
-                             * sizeof(nations_used));
-    memset(nations_used, 0,
-          game.playable_nation_count * sizeof(nations_used));
-
-    if (!client_is_observer()) {
-      /* Now close the conndlg and popup the races dialog. */
-      really_close_connection_dialog();
-      popup_races_dialog();
-    }
-  }
-}
-
-/**************************************************************************
   Take arrival of ruleset control packet to indicate that
   current allocated governments should be free'd, and new
   memory allocated for new size. The same for nations.
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.300
diff -u -r1.300 tilespec.c
--- client/tilespec.c   2 May 2005 15:42:52 -0000       1.300
+++ client/tilespec.c   3 May 2005 01:43:35 -0000
@@ -859,7 +859,7 @@
    * doesn't mess up too badly if we change tilesets while not connected
    * to a server.
    */
-  if (state < CLIENT_SELECT_RACE_STATE) {
+  if (state < CLIENT_GAME_RUNNING_STATE) {
     /* The ruleset data is not sent until this point. */
     return;
   }
Index: client/gui-gtk-2.0/dialogs.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/dialogs.c,v
retrieving revision 1.102
diff -u -r1.102 dialogs.c
--- client/gui-gtk-2.0/dialogs.c        29 Apr 2005 18:39:25 -0000      1.102
+++ client/gui-gtk-2.0/dialogs.c        3 May 2005 01:43:35 -0000
@@ -1691,7 +1691,7 @@
     gtk_dialog_new_with_buttons(_("What Nation Will You Be?"),
                                NULL,
                                0,
-                               _("_Disconnect"),
+                               _("Random Nation"),
                                GTK_RESPONSE_CANCEL,
                                GTK_STOCK_OK,
                                GTK_RESPONSE_ACCEPT,
@@ -1702,12 +1702,6 @@
   gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_CENTER_ON_PARENT);
   gtk_window_set_default_size(GTK_WINDOW(shell), -1, 310);
 
-  cmd = gtk_dialog_add_button(GTK_DIALOG(shell),
-      GTK_STOCK_QUIT, GTK_RESPONSE_CLOSE);
-  gtk_button_box_set_child_secondary(
-      GTK_BUTTON_BOX(GTK_DIALOG(shell)->action_area), cmd, TRUE);
-  gtk_widget_show(cmd);
-
   frame = gtk_frame_new(_("Select a nation"));
   gtk_container_add(GTK_CONTAINER(GTK_DIALOG(shell)->vbox), frame);
 
@@ -1998,7 +1992,7 @@
 /**************************************************************************
   ...
  **************************************************************************/
-void races_toggles_set_sensitive(bool *nations_used)
+void races_toggles_set_sensitive(void)
 {
   GtkTreeModel *model;
   GtkTreeIter it;
@@ -2015,11 +2009,14 @@
     model = gtk_tree_view_get_model(GTK_TREE_VIEW(races_nation_list[i]));
     if (gtk_tree_model_get_iter_first(model, &it)) {
       do {
-        int nation;
+        int nation_no;
+       struct nation_type *nation;
+
+        gtk_tree_model_get(model, &it, 0, &nation_no, -1);
+       nation = get_nation_by_idx(nation_no);
 
-        gtk_tree_model_get(model, &it, 0, &nation, -1);
+        chosen = nation->is_unavailable || nation->is_used;
 
-        chosen = nations_used[nation];
         gtk_list_store_set(GTK_LIST_STORE(model), &it, 1, chosen, -1);
 
       } while (gtk_tree_model_iter_next(model, &it));
@@ -2211,12 +2208,14 @@
     dsend_packet_nation_select_req(&aconnection, selected_nation,
                                   selected_sex, s, selected_city_style);
   } else if (response == GTK_RESPONSE_CLOSE) {
+    /* FIXME: remove this response */
     ui_exit();
-  } else {
-    popdown_races_dialog();
-    disconnect_from_server();
-    client_kill_server();
+    return;
+  } else if (response == GTK_RESPONSE_CANCEL) {
+    dsend_packet_nation_select_req(&aconnection, NO_NATION_SELECTED,
+                                  FALSE, "", 0);
   }
+  popdown_races_dialog();
 }
 
 
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.120
diff -u -r1.120 gui_main.c
--- client/gui-gtk-2.0/gui_main.c       1 May 2005 13:59:20 -0000       1.120
+++ client/gui-gtk-2.0/gui_main.c       3 May 2005 01:43:36 -0000
@@ -1230,11 +1230,26 @@
     gtk_list_store_clear(conn_model);
     conn_list_iterate(game.est_connections, pconn) {
       bool is_started = pconn->player ? pconn->player->is_started : FALSE;
+      const char *nation;
+      const char *leader;
+
+      if (!pconn->player) {
+       nation = "";
+       leader = "";
+      } else if (pconn->player->nation == NO_NATION_SELECTED) {
+       nation = _("Random");
+       leader = "";
+      } else {
+       nation = get_nation_name(pconn->player->nation);
+       leader = pconn->player->name;
+      }
 
       gtk_list_store_append(conn_model, &it);
       gtk_list_store_set(conn_model, &it,
                         0, pconn->username,
                         1, is_started,
+                        2, leader,
+                        3, nation,
                         -1);
     } conn_list_iterate_end;
   }
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.26
diff -u -r1.26 pages.c
--- client/gui-gtk-2.0/pages.c  1 May 2005 13:59:20 -0000       1.26
+++ client/gui-gtk-2.0/pages.c  3 May 2005 01:43:36 -0000
@@ -36,6 +36,8 @@
 #include "connectdlg_common.h"
 #include "packhand.h"
 
+#include "dialogs_g.h"
+
 #include "chatline.h"
 #include "connectdlg.h"
 #include "graphics.h"
@@ -928,6 +930,14 @@
 }
 
 /**************************************************************************
+  Called when "pick nation" is clicked.
+**************************************************************************/
+static void pick_nation_callback(GtkWidget *w, gpointer data)
+{
+  popup_races_dialog();
+}
+
+/**************************************************************************
   update the start page.
 **************************************************************************/
 static void update_start_page(void)
@@ -1035,7 +1045,8 @@
   gtk_box_pack_start(GTK_BOX(vbox), align, FALSE, FALSE, 8);
 
 
-  conn_model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN); 
+  conn_model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_BOOLEAN,
+                                 G_TYPE_STRING, G_TYPE_STRING);
 
   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(conn_model));
   g_object_unref(conn_model);
@@ -1052,6 +1063,16 @@
                                              -1, _("Ready"), rend,
                                              "active", 1, NULL);
 
+  rend = gtk_cell_renderer_text_new();
+  gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                             -1, _("Leader"), rend,
+                                             "text", 2, NULL);
+
+  rend = gtk_cell_renderer_text_new();
+  gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                             -1, _("Nation"), rend,
+                                             "text", 3, NULL);
+
   g_signal_connect(view, "button-press-event",
                   G_CALLBACK(show_conn_popup), NULL);
 
@@ -1100,6 +1121,11 @@
   g_signal_connect(button, "clicked",
       G_CALLBACK(main_callback), NULL);
 
+  button = gtk_stockbutton_new(GTK_STOCK_EDIT, _("Pick _Nation"));
+  g_signal_connect(button, "clicked",
+                  G_CALLBACK(pick_nation_callback), NULL);
+  gtk_container_add(GTK_CONTAINER(bbox), button);
+
   button = gtk_stockbutton_new(GTK_STOCK_EXECUTE, _("_Start"));
   g_signal_connect(button, "clicked",
       G_CALLBACK(start_start_callback), NULL);
Index: client/include/dialogs_g.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/include/dialogs_g.h,v
retrieving revision 1.23
diff -u -r1.23 dialogs_g.h
--- client/include/dialogs_g.h  30 Apr 2005 17:09:26 -0000      1.23
+++ client/include/dialogs_g.h  3 May 2005 01:43:36 -0000
@@ -31,7 +31,7 @@
 
 void popup_unit_select_dialog(struct tile *ptile);
 
-void races_toggles_set_sensitive(bool *nations_used);
+void races_toggles_set_sensitive(void);
 
 void popup_caravan_dialog(struct unit *punit,
                          struct city *phomecity, struct city *pdestcity);
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.184
diff -u -r1.184 game.h
--- common/game.h       2 May 2005 19:05:15 -0000       1.184
+++ common/game.h       3 May 2005 01:43:36 -0000
@@ -36,7 +36,6 @@
 
 enum server_states { 
   PRE_GAME_STATE, 
-  SELECT_RACES_STATE, 
   RUN_GAME_STATE,
   GAME_OVER_STATE
 };
@@ -44,7 +43,6 @@
 enum client_states { 
   CLIENT_BOOT_STATE,
   CLIENT_PRE_GAME_STATE,
-  CLIENT_SELECT_RACE_STATE,
   CLIENT_WAITING_FOR_GAME_START_STATE,
   CLIENT_GAME_RUNNING_STATE,
   CLIENT_GAME_OVER_STATE
Index: common/nation.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/nation.h,v
retrieving revision 1.44
diff -u -r1.44 nation.h
--- common/nation.h     2 May 2005 10:37:18 -0000       1.44
+++ common/nation.h     3 May 2005 01:43:36 -0000
@@ -101,6 +101,10 @@
   /* Groups which this nation is assigned to */
   int num_groups;
   struct nation_group **groups;
+
+  /* Unavailable nations aren't allowed in the scenario.  Used nations are
+   * those in use by another player. */
+  bool is_unavailable, is_used;
 };
 
 struct team {
@@ -136,6 +140,17 @@
 
 bool nation_in_group(struct nation_type* nation, const char* group_name);
 
+#define nations_iterate(nation)                                                
    \
+{                                                                          \
+  int NI_index;                                                                
    \
+                                                                           \
+  for (NI_index = 0; NI_index < game.playable_nation_count; NI_index++) {   \
+    struct nation_type *nation = get_nation_by_idx(NI_index);
+
+#define nations_iterate_end                                                \
+  }                                                                        \
+}
+
 #define team_iterate(PI_team)                                                 \
 {                                                                             \
   struct team *PI_team;                                                       \
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.113
diff -u -r1.113 packets.def
--- common/packets.def  2 May 2005 08:45:19 -0000       1.113
+++ common/packets.def  3 May 2005 01:43:36 -0000
@@ -279,13 +279,11 @@
 PACKET_SERVER_SHUTDOWN=8;sc,lsend
 end
 
-PACKET_NATION_UNAVAILABLE=9;sc,lsend
-  NATION nation;
-end
+PACKET_NATION_AVAILABLE=9;sc,lsend,is-info
+  NATION id; key
 
-# Sent to tell the client it needs to select a nation.  The unavailable
-# nations will be sent afterward via PACKET_NATION_UNAVAILABLE
-PACKET_SELECT_RACES=114;sc,lsend
+  BOOL is_unavailable;
+  BOOL is_used;
 end
 
 PACKET_NATION_SELECT_REQ=10;cs,dsend
@@ -295,9 +293,6 @@
   UINT8 city_style;
 end
 
-PACKET_NATION_SELECT_OK=11;sc,lsend
-end
-
 PACKET_GAME_STATE=12;post-send,post-recv,sc,dsend,lsend
   UINT32 value;
 end
@@ -1100,8 +1095,8 @@
   UINT8 fallout_tile_penalty[O_MAX]; /* % taken from output if polluted */
 end
 
-PACKET_RULESET_NATION=102;sc,lsend
-  NATION id;
+PACKET_RULESET_NATION=102;sc,lsend,is-info
+  NATION id; key
 
   STRING name[MAX_LEN_NAME];
   STRING name_plural[MAX_LEN_NAME];
Index: server/barbarian.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/barbarian.c,v
retrieving revision 1.89
diff -u -r1.89 barbarian.c
--- server/barbarian.c  2 May 2005 08:45:21 -0000       1.89
+++ server/barbarian.c  3 May 2005 01:43:37 -0000
@@ -96,7 +96,7 @@
         barbarians->economic.gold = 0;
         barbarians->is_alive = TRUE;
         barbarians->is_dying = FALSE;
-        pick_ai_player_name(game.nation_count - 1, barbarians->name);
+        pick_random_player_name(game.nation_count - 1, barbarians->name);
        sz_strlcpy(barbarians->username, ANON_USER_NAME);
         /* I need to make them to forget the map, I think */
        whole_map_iterate(ptile) {
@@ -119,7 +119,7 @@
   server_player_init(barbarians, TRUE);
 
   barbarians->nation = game.nation_count - 1;
-  pick_ai_player_name(game.nation_count - 1, barbarians->name);
+  pick_random_player_name(game.nation_count - 1, barbarians->name);
 
   game.nplayers++;
   game.nbarbarians++;
Index: server/connecthand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/connecthand.c,v
retrieving revision 1.44
diff -u -r1.44 connecthand.c
--- server/connecthand.c        1 May 2005 13:59:21 -0000       1.44
+++ server/connecthand.c        3 May 2005 01:43:37 -0000
@@ -580,8 +580,7 @@
   if (game.is_new_game
       && !pplayer->is_connected /* eg multiple controllers */
       && !pplayer->ai.control    /* eg created AI player */
-      && (server_state == PRE_GAME_STATE 
-          || server_state == SELECT_RACES_STATE)) {
+      && server_state == PRE_GAME_STATE) {
     server_remove_player(pplayer);
   } else {
     if (game.auto_ai_toggle
Index: server/meta.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/meta.c,v
retrieving revision 1.66
diff -u -r1.66 meta.c
--- server/meta.c       24 Dec 2004 04:01:48 -0000      1.66
+++ server/meta.c       3 May 2005 01:43:37 -0000
@@ -204,9 +204,6 @@
   case PRE_GAME_STATE:
     sz_strlcpy(state, "Pregame");
     break;
-  case SELECT_RACES_STATE:
-    sz_strlcpy(state, "Nation Select");
-    break;
   case RUN_GAME_STATE:
     sz_strlcpy(state, "Running");
     break;
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.371
diff -u -r1.371 plrhand.c
--- server/plrhand.c    2 May 2005 08:45:23 -0000       1.371
+++ server/plrhand.c    3 May 2005 01:43:37 -0000
@@ -1662,8 +1662,7 @@
 void server_remove_player(struct player *pplayer)
 {
   /* Not allowed after a game has started */
-  if (!(game.is_new_game && (server_state==PRE_GAME_STATE ||
-                            server_state==SELECT_RACES_STATE))) {
+  if (!(game.is_new_game && server_state == PRE_GAME_STATE)) {
     die("You can't remove players after the game has started!");
   }
 
@@ -1985,7 +1984,7 @@
   /* select a new name and nation for the copied player. */
   /* Rebel will always be an AI player */
   cplayer->nation = pick_available_nation(civilwar_nations);
-  pick_ai_player_name(cplayer->nation, cplayer->name);
+  pick_random_player_name(cplayer->nation, cplayer->name);
 
   sz_strlcpy(cplayer->username, ANON_USER_NAME);
   cplayer->is_connected = FALSE;
Index: server/ruleset.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/ruleset.c,v
retrieving revision 1.251
diff -u -r1.251 ruleset.c
--- server/ruleset.c    2 May 2005 08:45:23 -0000       1.251
+++ server/ruleset.c    3 May 2005 01:43:38 -0000
@@ -38,6 +38,7 @@
 #include "unit.h"
 
 #include "citytools.h"
+#include "plrhand.h"
 #include "script.h"
 
 #include "aiunit.h"            /* update_simple_ai_types */
@@ -2212,6 +2213,9 @@
     if (check_strlen(pl->legend, MAX_LEN_MSG, "Legend '%s' is too long")) {
       pl->legend[MAX_LEN_MSG - 1] = '\0';
     }
+
+    pl->is_unavailable = FALSE;
+    pl->is_used = FALSE;
   }
 
   /* Calculate parent nations.  O(n^2) algorithm. */
@@ -3056,6 +3060,19 @@
   lsend_packet_ruleset_game(dest, &misc_p);
 }
 
+/****************************************************************************
+  HACK: reset any nations that have been set so far.
+
+  FIXME: this should be moved into nationhand.c.
+****************************************************************************/
+static void reset_player_nations(void)
+{
+  players_iterate(pplayer) {
+    pplayer->nation = NO_NATION_SELECTED;
+  } players_iterate_end;
+  send_player_info_c(NULL, game.est_connections);
+}
+
 /**************************************************************************
   Loads the ruleset currently given in game.rulesetdir.
 
@@ -3069,6 +3086,7 @@
   freelog(LOG_NORMAL, _("Loading rulesets"));
 
   ruleset_data_free();
+  reset_player_nations();
 
   openload_ruleset_file(&techfile, "techs");
   load_tech_names(&techfile);
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.252
diff -u -r1.252 srv_main.c
--- server/srv_main.c   2 May 2005 10:37:18 -0000       1.252
+++ server/srv_main.c   3 May 2005 01:43:38 -0000
@@ -110,10 +110,7 @@
 
 static void end_turn(void);
 static void save_game_auto(const char *save_reason);
-static void generate_ai_players(void);
-static void mark_nation_as_used(Nation_type_id nation);
-static void announce_ai_player(struct player *pplayer);
-static void send_select_nation(struct player *pplayer);
+static void announce_player(struct player *pplayer);
 static void srv_loop(void);
 
 
@@ -134,9 +131,6 @@
 */
 bool force_end_of_sniff;
 
-/* List of which nations are available. */
-static bool *nations_available;
-
 /* this counter creates all the id numbers used */
 /* use get_next_id_number()                     */
 static unsigned short global_id_counter=100;
@@ -814,7 +808,7 @@
 
   con_puts(C_OK, _("Starting game."));
 
-  server_state=SELECT_RACES_STATE; /* loaded ??? */
+  server_state = RUN_GAME_STATE; /* loaded ??? */
   force_end_of_sniff = TRUE;
 }
 
@@ -1168,6 +1162,64 @@
   return TRUE;
 }
 
+/****************************************************************************
+  Send unavailable/used information for this nation out to everyone.
+****************************************************************************/
+static void send_nation_available(struct nation_type *nation)
+{
+  struct packet_nation_available packet;
+
+  packet.id = nation->index;
+  packet.is_unavailable = nation->is_unavailable;
+  packet.is_used = nation->is_used;
+
+  lsend_packet_nation_available(game.est_connections, &packet);
+}
+
+/****************************************************************************
+  Initialize the list of available nations.
+
+  Call this on server start, or when loading a scenario.
+****************************************************************************/
+static void init_available_nations(void)
+{
+  bool start_nations;
+  int i;
+
+  if (map.num_start_positions > 0) {
+    start_nations = TRUE;
+
+    for (i = 0; i < map.num_start_positions; i++) {
+      if (map.start_positions[i].nation == NO_NATION_SELECTED) {
+       start_nations = FALSE;
+       break;
+      }
+    }
+  } else {
+    start_nations = FALSE;
+  }
+
+  if (start_nations) {
+    nations_iterate(nation) {
+      nation->is_unavailable = TRUE;
+    } nations_iterate_end;
+    for (i = 0; i < map.num_start_positions; i++) {
+      Nation_type_id nation_no = map.start_positions[i].nation;
+      struct nation_type *nation = get_nation_by_idx(nation_no);
+
+      nation->is_unavailable = FALSE;
+    }
+  } else {
+    nations_iterate(nation) {
+      nation->is_unavailable = FALSE;
+    } nations_iterate_end;
+  }
+  nations_iterate(nation) {
+    nation->is_used = FALSE;
+    send_nation_available(nation);
+  } nations_iterate_end;
+}
+
 /**************************************************************************
 ...
 **************************************************************************/
@@ -1175,92 +1227,73 @@
                              Nation_type_id nation_no, bool is_male,
                              char *name, int city_style)
 {
-  int nation_used_count;
-  char message[1024];
+  const Nation_type_id old_nation_no = pplayer->nation;
 
-  if (server_state != SELECT_RACES_STATE) {
+  if (server_state != PRE_GAME_STATE) {
     freelog(LOG_ERROR, _("Trying to alloc nation outside "
-                        "of SELECT_RACES_STATE!"));
+                        "of pregame!"));
     return;
   }  
-  
-  /* check sanity of the packet sent by client */
-  if (nation_no < 0 || nation_no >= game.nation_count
-      || city_style < 0 || city_style >= game.styles_count
-      || city_style_has_requirements(&city_styles[city_style])
-      || !nations_available[nation_no]) {
-    return;
-  }
 
-  remove_leading_trailing_spaces(name);
-
-  if (!is_allowed_player_name(pplayer, nation_no, name,
-                             message, sizeof(message))) {
-    notify_player(pplayer, "%s", message);
-    send_select_nation(pplayer);
-    return;
-  }
-
-  name[0] = my_toupper(name[0]);
-
-  notify_conn_ex(game.game_connections, NULL, E_NATION_SELECTED,
-                _("%s is the %s ruler %s."), pplayer->username,
-                get_nation_name(nation_no), name);
-
-  /* inform player his choice was ok */
-  lsend_packet_nation_select_ok(pplayer->connections);
+  if (nation_no != NO_NATION_SELECTED) {
+    char message[1024];
+    struct nation_type *nation;
+
+    /* check sanity of the packet sent by client */
+    if (nation_no < 0 || nation_no >= game.nation_count
+       || city_style < 0 || city_style >= game.styles_count
+       || city_style_has_requirements(&city_styles[city_style])) {
+      return;
+    }
 
-  pplayer->nation = nation_no;
-  sz_strlcpy(pplayer->name, name);
-  pplayer->is_male = is_male;
-  pplayer->city_style = city_style;
+    nation = get_nation_by_idx(nation_no);
+    if (nation->is_unavailable) {
+      notify_conn_ex(pplayer->connections, NULL, E_NATION_SELECTED,
+                    _("%s nation is not available in this scenario."),
+                    nation->name);
+      return;
+    }
+    if (nation->is_unavailable) {
+      notify_conn_ex(pplayer->connections, NULL, E_NATION_SELECTED,
+                    _("%s nation is already in use."),
+                    nation->name);
+      return;
+    }
 
-  /* tell the other players, that the nation is now unavailable */
-  nation_used_count = 0;
+    remove_leading_trailing_spaces(name);
 
-  players_iterate(other_player) {
-    if (other_player->nation == NO_NATION_SELECTED) {
-      send_select_nation(other_player);
-    } else {
-      nation_used_count++;     /* count used nations */
+    if (!is_allowed_player_name(pplayer, nation_no, name,
+                               message, sizeof(message))) {
+      notify_conn_ex(pplayer->connections, NULL, E_NATION_SELECTED,
+                    "%s", message);
+      return;
     }
-  } players_iterate_end;
 
-  mark_nation_as_used(nation_no);
+    name[0] = my_toupper(name[0]);
 
-  /* if there's no nation left, reject remaining players, sorry */
-  if( nation_used_count == game.playable_nation_count ) {   /* barb */
-    players_iterate(other_player) {
-      if (other_player->nation == NO_NATION_SELECTED) {
-       freelog(LOG_NORMAL, _("No nations left: Removing player %s."),
-               other_player->name);
-       notify_player(other_player,
-                     _("Sorry, there are no nations left."));
-       server_remove_player(other_player);
-      }
-    } players_iterate_end;
+    notify_conn_ex(game.game_connections, NULL, E_NATION_SELECTED,
+                  _("%s is the %s ruler %s."), pplayer->username,
+                  get_nation_name(nation_no), name);
+
+    sz_strlcpy(pplayer->name, name);
+    pplayer->is_male = is_male;
+    pplayer->city_style = city_style;
+
+    nation->is_used = TRUE;
+    send_nation_available(nation);
   }
-}
 
-/**************************************************************************
- Sends the currently collected selected nations to the given player.
-**************************************************************************/
-static void send_select_nation(struct player *pplayer)
-{
-  struct packet_nation_unavailable packet;
-  Nation_type_id nation;
+  pplayer->nation = nation_no;
+  send_player_info_c(pplayer, game.est_connections);
 
-  lsend_packet_select_races(pplayer->connections);
+  if (old_nation_no != NO_NATION_SELECTED) {
+    struct nation_type *old_nation = get_nation_by_idx(old_nation_no);
 
-  for (nation = 0; nation < game.playable_nation_count; nation++) {
-    if (!nations_available[nation]) {
-      packet.nation = nation;
-      lsend_packet_nation_unavailable(pplayer->connections, &packet);
-    }
+    old_nation->is_used = FALSE;
+    send_nation_available(old_nation);
   }
 }
 
-
 /**************************************************************************
   Returns how much two nations looks good in the same game
 **************************************************************************/
@@ -1289,7 +1322,9 @@
   
   /* Determine which nations are available. */
   for (i = 0; i < game.playable_nation_count; i++) {
-    if (nations_available[i]) {
+    struct nation_type *nation = get_nation_by_idx(i);
+
+    if (!nation->is_unavailable && !nation->is_used) {
       available[count] = i;
       
       /* Increase the probablity of selecting those which have higher
@@ -1333,28 +1368,30 @@
    is chosen randomly.  (So if English are ruled by Elisabeth, she is
    female, but if "Player 1" rules English, may be male or female.)
 **************************************************************************/
-static void generate_ai_players(void)
+static void generate_players(void)
 {
   Nation_type_id nation;
   char player_name[MAX_LEN_NAME];
-  struct player *pplayer;
   int i, old_nplayers;
 
   /* Select nations for AI players generated with server
    * 'create <name>' command
    */
-  for (i=0; i<game.nplayers; i++) {
-    pplayer = &game.players[i];
-    
+  players_iterate(pplayer) {
+    ai_data_analyze_rulesets(pplayer);
+
     if (pplayer->nation != NO_NATION_SELECTED) {
       continue;
     }
 
-    /* See if the AI player matches a known leader name. */
+    /* See if the player name matches a known leader name. */
     for (nation = 0; nation < game.playable_nation_count; nation++) {
+      struct nation_type *n = get_nation_by_idx(nation);
+
       if (check_nation_leader_name(nation, pplayer->name)
-         && nations_available[nation]) {
-       mark_nation_as_used(nation);
+         && !n->is_unavailable
+         && !n->is_used) {
+       n->is_used = TRUE;
        pplayer->nation = nation;
        pplayer->city_style = get_nation_city_style(nation);
        pplayer->is_male = get_nation_leader_sex(nation, pplayer->name);
@@ -1366,40 +1403,26 @@
     }
 
     nation = select_random_nation();
-    if (nation == NO_NATION_SELECTED) {
-      freelog(LOG_NORMAL,
-             _("Ran out of nations.  AI controlled player %s not created."),
-             pplayer->name);
-      server_remove_player(pplayer); 
-      /*
-       * Below decrement loop index 'i' so that the loop is redone with
-       * the current index (if 'i' is still less than new game.nplayers).
-       * This is because subsequent players in list will have been shifted
-       * down one spot by the remove, and may need handling.
-       */
-      i--;  
-      continue;
+    assert(nation != NO_NATION_SELECTED);
+
+    get_nation_by_idx(nation)->is_used = TRUE;
+    pplayer->nation = nation;
+    pplayer->city_style = get_nation_city_style(nation);
+
+    if (!pplayer->is_connected) {
+      /* Keep the player name. */
+      pplayer->is_male = (myrand(2) == 1);
     } else {
-      mark_nation_as_used(nation);
-      pplayer->nation = nation;
-      pplayer->city_style = get_nation_city_style(nation);
+      /* FIXME: need to generate a leader name. */
       pplayer->is_male = (myrand(2) == 1);
     }
 
-    announce_ai_player(pplayer);
-  }
+    announce_player(pplayer);
+  } players_iterate_end;
   
   /* Create and pick nation and name for AI players needed to bring the
    * total number of players to equal game.aifill
    */
-
-  if (game.playable_nation_count < game.aifill) {
-    game.aifill = game.playable_nation_count;
-    freelog(LOG_NORMAL,
-            _("Nation count smaller than aifill; aifill reduced to %d."),
-             game.playable_nation_count);
-  }
-
   if (game.max_players < game.aifill) {
     game.aifill = game.max_players;
     freelog(LOG_NORMAL,
@@ -1420,10 +1443,12 @@
   }
 
   for(;game.nplayers < game.aifill + i;) {
+    struct player *pplayer;
+
     nation = select_random_nation();
     assert(nation != NO_NATION_SELECTED);
-    mark_nation_as_used(nation);
-    pick_ai_player_name(nation, player_name);
+    get_nation_by_idx(nation)->is_used = TRUE;
+    pick_random_player_name(nation, player_name);
 
     old_nplayers = game.nplayers;
     pplayer = get_player(old_nplayers);
@@ -1461,7 +1486,7 @@
 }
 
 /*************************************************************************
- Used in pick_ai_player_name() below; buf has size at least MAX_LEN_NAME;
+ Used in pick_random_player_name() below; buf has size at least MAX_LEN_NAME;
 *************************************************************************/
 static bool good_name(char *ptry, char *buf) {
   if (!(find_player_by_name(ptry) || find_player_by_user(ptry))) {
@@ -1472,14 +1497,14 @@
 }
 
 /*************************************************************************
- pick_ai_player_name() - Returns a random ruler name picked from given nation
+  Returns a random ruler name picked from given nation
      ruler names, given that nation's number. If that player name is already 
      taken, iterates through all leader names to find unused one. If it fails
      it iterates through "Player 1", "Player 2", ... until an unused name
      is found.
  newname should point to a buffer of size at least MAX_LEN_NAME.
 *************************************************************************/
-void pick_ai_player_name(Nation_type_id nation, char *newname) 
+void pick_random_player_name(Nation_type_id nation, char *newname) 
 {
    int i, names_count;
    struct leader *leaders;
@@ -1509,21 +1534,13 @@
 }
 
 /*************************************************************************
-  Simply mark the nation as unavailable.
-*************************************************************************/
-static void mark_nation_as_used (Nation_type_id nation) 
-{
-  assert(nations_available[nation]);
-  nations_available[nation] = FALSE;
-}
-
-/*************************************************************************
 ...
 *************************************************************************/
-static void announce_ai_player (struct player *pplayer) {
-   freelog(LOG_NORMAL, _("AI is controlling the %s ruled by %s."),
-                    get_nation_name_plural(pplayer->nation),
-                    pplayer->name);
+static void announce_player (struct player *pplayer)
+{
+   freelog(LOG_NORMAL,
+          _("%s rules the %s."), pplayer->name,
+          get_nation_name_plural(pplayer->nation));
 
   players_iterate(other_player) {
     notify_player(other_player,
@@ -1749,8 +1766,7 @@
 **************************************************************************/
 static void srv_loop(void)
 {
-  int i;
-  bool start_nations;
+  init_available_nations();
 
   freelog(LOG_NORMAL, _("Now accepting new client connections."));
   while(server_state == PRE_GAME_STATE) {
@@ -1759,39 +1775,6 @@
 
   (void) send_server_info_to_metaserver(META_INFO);
 
-  nations_available
-    = fc_realloc(nations_available,
-                game.playable_nation_count * sizeof(*nations_available));
-
-main_start_players:
-
-  if (map.num_start_positions > 0) {
-    start_nations = TRUE;
-
-    for (i = 0; i < map.num_start_positions; i++) {
-      if (map.start_positions[i].nation == NO_NATION_SELECTED) {
-       start_nations = FALSE;
-       break;
-      }
-    }
-  } else {
-    start_nations = FALSE;
-  }
-
-  if (start_nations) {
-    for (i = 0; i < game.playable_nation_count; i++) {
-      nations_available[i] = FALSE;
-    }
-    for (i = 0; i < map.num_start_positions; i++) {
-      nations_available[map.start_positions[i].nation] = TRUE;
-    }
-    
-  } else {
-    for (i = 0; i < game.playable_nation_count; i++) {
-      nations_available[i] = TRUE;
-    }
-  }
-
   if (game.auto_ai_toggle) {
     players_iterate(pplayer) {
       if (!pplayer->is_connected && !pplayer->ai.control) {
@@ -1800,48 +1783,6 @@
     } players_iterate_end;
   }
 
-  /* Allow players to select a nation (case new game).
-   * AI players may not yet have a nation; these will be selected
-   * in generate_ai_players() later
-   */
-  server_state = RUN_GAME_STATE;
-  players_iterate(pplayer) {
-    ai_data_analyze_rulesets(pplayer);
-    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;
-    }
-  } players_iterate_end;
-
-  while(server_state == SELECT_RACES_STATE) {
-    bool flag = FALSE;
-
-    sniff_packets();
-
-    players_iterate(pplayer) {
-      if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) {
-       flag = TRUE;
-       break;
-      }
-    } players_iterate_end;
-
-    if (!flag) {
-      if (game.nplayers > 0) {
-       server_state = RUN_GAME_STATE;
-      } else {
-       con_write(C_COMMENT,
-                 _("Last player has disconnected: will need to restart."));
-       server_state = PRE_GAME_STATE;
-       while(server_state == PRE_GAME_STATE) {
-         sniff_packets();
-       }
-       goto main_start_players;
-      }
-    }
-  }
-
   init_game_seed();
 
 #ifdef TEST_RANDOM /* not defined anywhere, set it if you want it */
@@ -1852,7 +1793,7 @@
 #endif
 
   if (game.is_new_game) {
-    generate_ai_players();
+    generate_players();
   }
   final_ruleset_adjustments();
    
Index: server/srv_main.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.h,v
retrieving revision 1.31
diff -u -r1.31 srv_main.h
--- server/srv_main.h   2 May 2005 10:37:18 -0000       1.31
+++ server/srv_main.h   3 May 2005 01:43:38 -0000
@@ -59,7 +59,7 @@
 bool handle_packet_input(struct connection *pconn, void *packet, int type);
 void start_game(void);
 void save_game(char *orig_filename, const char *save_reason);
-void pick_ai_player_name(Nation_type_id nation, char *newname);
+void pick_random_player_name(Nation_type_id nation, char *newname);
 void send_all_info(struct conn_list *dest);
 void check_for_full_turn_done(void);
 
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.403
diff -u -r1.403 stdinhand.c
--- server/stdinhand.c  2 May 2005 10:37:18 -0000       1.403
+++ server/stdinhand.c  3 May 2005 01:43:40 -0000
@@ -754,11 +754,7 @@
 **************************************************************************/
 static bool save_command(struct connection *caller, char *arg, bool check)
 {
-  if (server_state==SELECT_RACES_STATE) {
-    cmd_reply(CMD_SAVE, caller, C_SYNTAX,
-             _("The game cannot be saved before it is started."));
-    return FALSE;
-  } else if (!check) {
+  if (!check) {
     save_game(arg, "User request");
   }
   return TRUE;
@@ -948,8 +944,7 @@
     return FALSE;
   }
 
-  if (!(game.is_new_game && (server_state==PRE_GAME_STATE ||
-                            server_state==SELECT_RACES_STATE))) {
+  if (!(game.is_new_game && server_state == PRE_GAME_STATE)) {
     cmd_reply(CMD_REMOVE, caller, C_FAIL,
              _("Players cannot be removed once the game has started."));
     return FALSE;
@@ -2645,9 +2640,7 @@
 {
   int i = 0, ntokens = 0;
   char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];  
-  bool is_newgame = (server_state == PRE_GAME_STATE || 
-                     server_state == SELECT_RACES_STATE) && game.is_new_game;
-  
+  bool is_newgame = server_state == PRE_GAME_STATE && game.is_new_game;
   enum m_pre_result result;
   struct connection *pconn = NULL;
   struct player *pplayer = NULL;
@@ -2797,9 +2790,7 @@
 {
   int i = 0, ntokens = 0;
   char buf[MAX_LEN_CONSOLE_LINE], *arg[2], msg[MAX_LEN_MSG];
-  bool is_newgame = (server_state == PRE_GAME_STATE || 
-                     server_state == SELECT_RACES_STATE) && game.is_new_game;
-
+  bool is_newgame = server_state == PRE_GAME_STATE && game.is_new_game;
   enum m_pre_result match_result;
   struct connection *pconn = NULL;
   struct player *pplayer = NULL;
@@ -2971,8 +2962,7 @@
   enum m_pre_result match_result;
   struct connection *pconn = NULL;
   struct player *pplayer = NULL;
-  bool is_newgame = (server_state == PRE_GAME_STATE || 
-                     server_state == SELECT_RACES_STATE) && game.is_new_game;
+  bool is_newgame = server_state == PRE_GAME_STATE && game.is_new_game;
   bool one_obs_among_many = FALSE, res = FALSE;
 
   sz_strlcpy(buf, str);
@@ -3224,7 +3214,7 @@
   if (!check) {
     cmd_reply(CMD_RULESETDIR, caller, C_OK, 
               _("Ruleset directory set to \"%s\""), str);
-    sz_strlcpy(game.rulesetdir, str);
+    sz_strlcpy(game.rulesetdir, str);    
     load_rulesets();
   }
   return TRUE;
@@ -3653,11 +3643,6 @@
               _("Cannot start the game: the game is waiting for all clients "
               "to disconnect."));
     return FALSE;
-  case SELECT_RACES_STATE:
-    /* TRANS: given when /start is invoked during nation selection. */
-    cmd_reply(CMD_START_GAME, caller, C_FAIL,
-              _("Cannot start the game: it has already been started."));
-    return FALSE;
   case RUN_GAME_STATE:
     /* TRANS: given when /start is invoked while the game is running. */
     cmd_reply(CMD_START_GAME, caller, C_FAIL,

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