wesnoth-cvs-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Wesnoth-cvs-commits] wesnoth/src Makefile.am game.cpp gamestatus.hpp...


From: Philippe Plantier
Subject: [Wesnoth-cvs-commits] wesnoth/src Makefile.am game.cpp gamestatus.hpp...
Date: Sun, 20 Feb 2005 17:30:29 -0500

CVSROOT:        /cvsroot/wesnoth
Module name:    wesnoth
Branch:         
Changes by:     Philippe Plantier <address@hidden>      05/02/20 22:30:29

Modified files:
        src            : Makefile.am game.cpp gamestatus.hpp 
                         multiplayer.cpp multiplayer.hpp 
                         multiplayer_connect.cpp multiplayer_connect.hpp 
                         multiplayer_lobby.cpp multiplayer_lobby.hpp 
        src/server     : game.cpp game.hpp server.cpp 
        src/widgets    : combo.cpp combo.hpp scrollpane.cpp 
                         scrollpane.hpp textbox.cpp textbox.hpp 
Added files:
        src            : leader_list.cpp leader_list.hpp 
                         multiplayer_wait.cpp multiplayer_wait.hpp 
Removed files:
        src            : multiplayer_client.cpp multiplayer_client.hpp 

Log message:
        Completely rewrote the "multiplayer lobby" and "multiplayer game 
creation" code, and modified the associated server code.
        
        Added the ability to kick users in the "game creation" screen
        Added the ability for users to switch sides in the "game creation" 
screen
        Added the name of the previous user for each position, on the "game 
creation" screen, when loading saves.
        Fixed several bugs.
        Certainly introduced several more.

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/leader_list.cpp?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/leader_list.hpp?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_wait.cpp?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_wait.hpp?rev=1.1
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/Makefile.am.diff?tr1=1.70&tr2=1.71&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/game.cpp.diff?tr1=1.194&tr2=1.195&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/gamestatus.hpp.diff?tr1=1.36&tr2=1.37&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer.cpp.diff?tr1=1.134&tr2=1.135&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer.hpp.diff?tr1=1.24&tr2=1.25&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_connect.cpp.diff?tr1=1.103&tr2=1.104&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_connect.hpp.diff?tr1=1.24&tr2=1.25&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_lobby.cpp.diff?tr1=1.57&tr2=1.58&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_lobby.hpp.diff?tr1=1.8&tr2=1.9&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/server/game.cpp.diff?tr1=1.28&tr2=1.29&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/server/game.hpp.diff?tr1=1.16&tr2=1.17&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/server/server.cpp.diff?tr1=1.65&tr2=1.66&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/combo.cpp.diff?tr1=1.27&tr2=1.28&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/combo.hpp.diff?tr1=1.19&tr2=1.20&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/scrollpane.cpp.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/scrollpane.hpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/textbox.cpp.diff?tr1=1.68&tr2=1.69&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/textbox.hpp.diff?tr1=1.36&tr2=1.37&r1=text&r2=text

Patches:
Index: wesnoth/src/Makefile.am
diff -u wesnoth/src/Makefile.am:1.70 wesnoth/src/Makefile.am:1.71
--- wesnoth/src/Makefile.am:1.70        Sun Feb 20 20:11:27 2005
+++ wesnoth/src/Makefile.am     Sun Feb 20 22:30:27 2005
@@ -56,6 +56,7 @@
                  intro.cpp \
                  key.cpp \
                  language.cpp \
+                 leader_list.cpp \
                  log.cpp \
                  map.cpp \
                  map_label.cpp \
@@ -63,8 +64,10 @@
                  mapgen_dialog.cpp \
                  mouse.cpp \
                  multiplayer.cpp \
-                 multiplayer_client.cpp \
+                 multiplayer_ui.cpp \
+                 multiplayer_wait.cpp \
                  multiplayer_connect.cpp \
+                 multiplayer_create.cpp \
                  multiplayer_lobby.cpp \
                  network.cpp \
                  network_worker.cpp \
@@ -140,6 +143,7 @@
                  intro.hpp \
                  key.hpp \
                  language.hpp \
+                 leader_list.hpp \
                  log.hpp \
                  map.hpp \
                  map_label.hpp \
@@ -147,8 +151,10 @@
                  mapgen_dialog.hpp \
                  mouse.hpp \
                  multiplayer.hpp \
-                 multiplayer_client.hpp \
+                 multiplayer_ui.hpp \
+                 multiplayer_wait.hpp \
                  multiplayer_connect.hpp \
+                 multiplayer_create.hpp \
                  multiplayer_lobby.hpp \
                  network.hpp \
                  network_worker.hpp \
Index: wesnoth/src/game.cpp
diff -u wesnoth/src/game.cpp:1.194 wesnoth/src/game.cpp:1.195
--- wesnoth/src/game.cpp:1.194  Sun Feb 20 21:45:21 2005
+++ wesnoth/src/game.cpp        Sun Feb 20 22:30:27 2005
@@ -1,4 +1,4 @@
-/* $Id: game.cpp,v 1.194 2005/02/20 21:45:21 silene Exp $ */
+/* $Id: game.cpp,v 1.195 2005/02/20 22:30:27 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -35,7 +35,6 @@
 #include "log.hpp"
 #include "mapgen.hpp"
 #include "multiplayer.hpp"
-#include "multiplayer_client.hpp"
 #include "network.hpp"
 #include "pathfind.hpp"
 #include "playlevel.hpp"
@@ -1302,25 +1301,20 @@
                        std::vector<std::string> chat;
                        config game_data;
 
-                       const std::string controller = (res == 2 ? "network" : 
(res == 3 ? "human" : "ai"));
+                       const mp::controller cntr = (res == 2 ? 
+                                       mp::CNTR_NETWORK : 
+                                       (res == 3 ? mp::CNTR_LOCAL : 
mp::CNTR_COMPUTER ));
                        const bool is_server = res == 2;
 
-                       multiplayer_game_setup_dialog 
mp_dialog(disp(),units_data_,game_config_,state_,is_server,controller);
-                       lobby::RESULT res = lobby::CONTINUE;
-                       while(res == lobby::CONTINUE) {
-                               res = 
lobby::enter(disp(),game_data,game_config_,&mp_dialog,chat);
-                       }
+                       mp::start_server(disp(), game_config_, units_data_, 
cntr, is_server);
 
-                       if(res == lobby::CREATE) {
-                               mp_dialog.start_game();
-                       }
                } else if(res == 0 || res == 1) {
                        std::string host;
                        if(res == 0) {
                                host = preferences::official_network_host();
                        }
 
-                       
play_multiplayer_client(disp(),units_data_,game_config_,state_,host);
+                       mp::start_client(disp(), game_config_, units_data_, 
host);
                }
        } catch(gamestatus::load_game_failed& e) {
                gui::show_error_message(disp(), _("The game could not be 
loaded: ") + e.message);
Index: wesnoth/src/gamestatus.hpp
diff -u wesnoth/src/gamestatus.hpp:1.36 wesnoth/src/gamestatus.hpp:1.37
--- wesnoth/src/gamestatus.hpp:1.36     Sat Dec  4 23:44:09 2004
+++ wesnoth/src/gamestatus.hpp  Sun Feb 20 22:30:27 2005
@@ -1,4 +1,4 @@
-/* $Id: gamestatus.hpp,v 1.36 2004/12/04 23:44:09 isaaccp Exp $ */
+/* $Id: gamestatus.hpp,v 1.37 2005/02/20 22:30:27 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -128,7 +128,7 @@
 
 //object which holds all the data needed to start a scenario.
 //i.e. this is the object serialized to disk when saving/loading a game.
-//is also the object which needs to be created to start a nwe game
+//is also the object which needs to be created to start a new game
 struct game_state
 {
        game_state() : difficulty("NORMAL") {}
Index: wesnoth/src/multiplayer.cpp
diff -u wesnoth/src/multiplayer.cpp:1.134 wesnoth/src/multiplayer.cpp:1.135
--- wesnoth/src/multiplayer.cpp:1.134   Sun Jan  2 21:28:05 2005
+++ wesnoth/src/multiplayer.cpp Sun Feb 20 22:30:27 2005
@@ -1,7 +1,7 @@
-/* $Id: multiplayer.cpp,v 1.134 2005/01/02 21:28:05 silene Exp $ */
+/* $Id: multiplayer.cpp,v 1.135 2005/02/20 22:30:27 gruikya Exp $ */
 /*
-   Copyright (C) 2003 by David White <address@hidden>
-   Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
+   Copyright (C)
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License.
@@ -11,593 +11,335 @@
    See the COPYING file for more details.
 */
 
-#include "global.hpp"
-
-#include "cursor.hpp"
-#include "events.hpp"
-#include "filesystem.hpp"
-#include "font.hpp"
-#include "language.hpp"
-#include "log.hpp"
-#include "image.hpp"
-#include "key.hpp"
-#include "log.hpp"
-#include "mapgen.hpp"
 #include "multiplayer.hpp"
+#include "multiplayer_ui.hpp"
 #include "multiplayer_connect.hpp"
-#include "multiplayer_client.hpp"
-#include "network.hpp"
-#include "playlevel.hpp"
+#include "multiplayer_wait.hpp"
+#include "multiplayer_lobby.hpp"
+#include "multiplayer_create.hpp"
 #include "preferences.hpp"
-#include "replay.hpp"
-#include "scoped_resource.hpp"
-#include "show_dialog.hpp"
-#include "util.hpp"
-#include "widgets/textbox.hpp"
-#include "widgets/button.hpp"
-#include "widgets/combo.hpp"
-#include "widgets/menu.hpp"
-#include "widgets/slider.hpp"
-#include "widgets/widget.hpp"
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
+#include "game_config.hpp"
+#include "log.hpp"
+#include "playlevel.hpp"
+#include "network.hpp"
 
-#define LOG_G lg::info(lg::general)
 #define LOG_NW lg::info(lg::network)
-#define LOG_DP lg::info(lg::display)
-#define ERR_CF lg::err(lg::config)
 
-network_game_manager::~network_game_manager()
-{
-       if(network::nconnections() > 0) {
-               LOG_NW << "sending leave_game\n";
-               config cfg;
-               cfg.add_child("leave_game");
-               network::send_data(cfg);
-               LOG_NW << "sent leave_game\n";
-       }
-}
+namespace {
 
-multiplayer_game_setup_dialog::multiplayer_game_setup_dialog(
-                              display& disp, game_data& units_data,
-                              const config& cfg, game_state& state, bool 
server, const std::string& controller)
-        : disp_(disp), units_data_(units_data), cfg_(cfg), state_(state), 
server_(server), level_(NULL), map_selection_(-1),
-                 maps_menu_(NULL), turns_slider_(NULL), 
village_gold_slider_(NULL), xp_modifier_slider_(NULL),
-                 fog_game_(NULL), shroud_game_(NULL), observers_game_(NULL),
-          cancel_game_(NULL), launch_game_(NULL), regenerate_map_(NULL), 
generator_settings_(NULL),
-                 era_combo_(NULL), vision_combo_(NULL), name_entry_(NULL), 
generator_(NULL), controller_(controller)
+class network_game_manager
 {
-       LOG_DP << "setup dialog ctor\n";
-
-       state_.players.clear();
-       state_.variables.clear();
-
-       //build the list of scenarios to play
-       get_files_in_dir(get_user_data_dir() + 
"/editor/maps",&user_maps_,NULL,FILE_NAME_ONLY);
-
-       map_options_ = user_maps_;
-
-       const config::child_list& levels = cfg.get_children("multiplayer");
-       for(config::child_list::const_iterator j = levels.begin(); j != 
levels.end(); ++j){
-               map_options_.push_back((**j)["name"]);
-       }
-
-       //add the 'load game' option
-       map_options_.push_back(_("Load Game..."));
-
-       //create the scenarios menu
-       maps_menu_.assign(new gui::menu(disp_,map_options_));
-       maps_menu_->set_numeric_keypress_selection(false);
-
-       turns_slider_.assign(new gui::slider(disp_));
-       turns_slider_->set_min(20);
-       turns_slider_->set_max(100);
-       turns_slider_->set_value(preferences::turns());
-       turns_slider_->set_help_string(_("The maximum turns the game will go 
for"));
-
-       village_gold_slider_.assign(new gui::slider(disp_));
-       village_gold_slider_->set_min(1);
-       village_gold_slider_->set_max(5);
-       village_gold_slider_->set_value(preferences::village_gold());
-       village_gold_slider_->set_help_string(_("The amount of income each 
village yields per turn"));
-
-       xp_modifier_slider_.assign(new gui::slider(disp_));
-       xp_modifier_slider_->set_min(25);
-       xp_modifier_slider_->set_max(200);
-       xp_modifier_slider_->set_value(preferences::xp_modifier());
-       xp_modifier_slider_->set_increment(10);
-       xp_modifier_slider_->set_help_string(_("The amount of experience a unit 
needs to advance"));
-
-       fog_game_.assign(new gui::button(disp_,_("Fog Of 
War"),gui::button::TYPE_CHECK));
-       fog_game_->set_check(preferences::fog());
-       fog_game_->set_help_string(_("Enemy units cannot be seen unless they 
are in range of your units"));
-
-       shroud_game_.assign(new 
gui::button(disp_,_("Shroud"),gui::button::TYPE_CHECK));
-       shroud_game_->set_check(preferences::shroud());
-       shroud_game_->set_help_string(_("The map is unknown until your units 
explore it"));
-
-       observers_game_.assign(new 
gui::button(disp_,_("Observers"),gui::button::TYPE_CHECK));
-       observers_game_->set_check(preferences::allow_observers());
-       observers_game_->set_help_string(_("Allow users who are not playing to 
watch the game"));
+public:
+       ~network_game_manager()
+       {
+               if(network::nconnections() > 0) {
+                       LOG_NW << "sending leave_game\n";
+                       config cfg;
+                       cfg.add_child("leave_game");
+                       network::send_data(cfg);
+                       LOG_NW << "sent leave_game\n";
+               }
+       };
+};
 
-       cancel_game_.assign(new gui::button(disp_,_("Cancel")));
-       launch_game_.assign(new gui::button(disp_,_("Ok")));
 
-       regenerate_map_.assign(new gui::button(disp_,_("Regenerate")));
+void run_lobby_loop(display& disp, mp::ui& ui)
+{
+       disp.video().modeChanged();
+       bool first = true;
 
-       generator_settings_.assign(new gui::button(disp_,_("Settings...")));
+       while (ui.get_result() == mp::ui::CONTINUE) {
+               if (disp.video().modeChanged() || first) {
+                       SDL_Rect lobby_pos = { 0, 0, disp.video().getx(), 
disp.video().gety() };
+                       ui.set_location(lobby_pos);
+                       first = false;
+               }
 
-       //The possible vision settings
-       std::vector<std::string> vision_types;
-       vision_types.push_back(_("Share View"));
-       vision_types.push_back(_("Share Maps"));
-       vision_types.push_back(_("Share None"));
-       vision_combo_.assign(new gui::combo(disp_,vision_types));
+               events::raise_process_event();
+               events::raise_draw_event();
+               events::pump();
 
-       //the possible eras to play
-       const config::child_list& era_list = cfg.get_children("era");
-       std::vector<std::string> eras;
-       for(config::child_list::const_iterator er = era_list.begin(); er != 
era_list.end(); ++er) {
-               eras.push_back((**er)["name"]);
-       }
+               ui.process_network();
 
-       if(eras.empty()) {
-               gui::show_dialog(disp_,NULL,"",_("No multiplayer 
sides."),gui::OK_ONLY);
-               ERR_CF << "no eras found\n";
-               throw config::error("no eras found");
+               disp.video().flip();
+               SDL_Delay(20);
        }
-
-       era_combo_.assign(new gui::combo(disp_,eras));
-       era_combo_->set_selected(preferences::era());
-
-       LOG_DP << "end setup dialog ctor\n";
 }
 
-void multiplayer_game_setup_dialog::set_area(const SDL_Rect& area)
-{
-       LOG_DP << "setup dialog set_area\n";
-
-       area_ = area;
-
-       map_selection_ = -1;
+enum server_type {
+       ABORT_SERVER,
+       WESNOTHD_SERVER,
+       SIMPLE_SERVER
+};
 
-       // Dialog width and height
-       int width = int(area.w);
-       int height = int(area.h);
-       const int left = area.x;
-       const int top = area.y;
-       const int border_size = 6;
-       const int right = left + width;
-       const int bottom = top + height;
-
-       int xpos = left + border_size;
-       int ypos = top + gui::draw_dialog_title(left,top,&disp_,_("Create 
Game")).h + border_size;
-
-       //Name Entry
-       ypos += 
font::draw_text(&disp_,disp_.screen_area(),font::SIZE_SMALL,font::GOOD_COLOUR,
-                               _("Name of game:"),xpos,ypos).h + border_size;
-       string_map i18n_symbols;
-       i18n_symbols["login"] = preferences::login();
-       name_entry_.assign(new gui::textbox(disp_,width-20,vgettext("$login's 
game", i18n_symbols)));
-       name_entry_->set_location(xpos,ypos);
-       name_entry_->set_dirty();
-
-       ypos += name_entry_->location().h + border_size;
-
-       const int minimap_width = 200;
-
-       //the map selection menu goes near the middle of the dialog, to the 
right of
-       //the minimap
-       const int map_label_height = 
font::draw_text(&disp_,disp_.screen_area(),font::SIZE_SMALL,font::GOOD_COLOUR,
-                                                    _("Map to play:"),xpos + 
minimap_width + border_size,ypos).h;
-
-       maps_menu_->set_max_width(area.x + area.w - (xpos + minimap_width) - 
250);
-       maps_menu_->set_max_height(area.y + area.h - (ypos + map_label_height));
-       maps_menu_->set_items(map_options_);
-       maps_menu_->set_location(xpos + minimap_width + border_size,ypos + 
map_label_height + border_size);
-       maps_menu_->move_selection(preferences::map());
-       maps_menu_->set_dirty();
-
-       SDL_Rect rect;
-
-       //the sliders and other options on the right side of the dialog
-       rect.x = xpos + minimap_width + maps_menu_->width() + border_size;
-       rect.y = ypos;
-       rect.w = maximum<int>(0,right - border_size - rect.x);
-       //a font sized "12" isn't necessarily 12 pixel high.
-       rect.h = font::get_max_height(font::SIZE_SMALL);
-
-       turns_restorer_ = surface_restorer(&disp_.video(),rect);
-
-       rect.y += rect.h + border_size + 1;
-
-       turns_slider_->set_location(rect);
-       turns_slider_->set_dirty();
-
-       //Village Gold
-       rect.y += rect.h + border_size + 1;
-
-       village_gold_restorer_ = surface_restorer(&disp_.video(),rect);
-
-       rect.y += rect.h + border_size + 1;
-
-       village_gold_slider_->set_location(rect);
-       village_gold_slider_->set_dirty();
-
-       //Experience Modifier
-       rect.y += rect.h + border_size + 1;
-
-       xp_restorer_ = surface_restorer(&disp_.video(),rect);
-
-       rect.y += rect.h + border_size + 1;
-
-       xp_modifier_slider_->set_location(rect);
-       xp_modifier_slider_->set_dirty();
-
-       //FOG of war
-       rect.y += rect.h + border_size + 1;
-
-       fog_game_->set_location(rect.x,rect.y);
-       fog_game_->set_dirty();
-
-       rect.y += fog_game_->location().h + border_size + 1;
-
-       //Shroud
-       shroud_game_->set_location(rect.x,rect.y);
-       shroud_game_->set_dirty();
-
-       rect.y += shroud_game_->location().h + border_size;
-
-       //Observers
-       observers_game_->set_location(rect.x,rect.y);
-       observers_game_->set_dirty();
-
-       rect.y += observers_game_->location().h + border_size;
-
-       //Ally shared view settings
-       vision_combo_->set_location(rect.x,rect.y);
-
-       rect.y += vision_combo_->height() + border_size;
+server_type open_connection(display& disp, const std::string& host)
+{
+       std::string h = host;
 
-       gui::button* left_button = launch_game_;
-       gui::button* right_button = cancel_game_;
+       if(h.empty()) {
+               h = preferences::network_host();
+               const int res = gui::show_dialog(disp, NULL, _("Connect to 
Host"), "",
+                               gui::OK_CANCEL, NULL, NULL,
+                               _("Choose host to connect to") + std::string(": 
"), &h);
 
-#ifdef OK_BUTTON_ON_RIGHT
-       std::swap(left_button,right_button);
-#endif
+               if(res != 0 || h.empty()) {
+                       return ABORT_SERVER;
+               }
+       }
 
-       //Buttons
-       right_button->set_location(right - right_button->width() - 
gui::ButtonHPadding,bottom - right_button->height() - gui::ButtonVPadding);
-       left_button->set_location(right - right_button->width() - 
left_button->width() - gui::ButtonHPadding*2,bottom - left_button->height() - 
gui::ButtonVPadding);
+       network::connection sock;
 
-       cancel_game_->set_dirty();
-       launch_game_->set_dirty();
-       
+       const int pos = h.find_first_of(":");
+ 
+       if(pos == -1) {
+               sock = network::connect(h);
+       } else {
+               sock = network::connect(h.substr(0,pos),
+                               lexical_cast_default<int>(h.substr(pos+1), 
15000));
+       }
+
+       if (!sock) {
+               return ABORT_SERVER;
+       }
+
+       preferences::set_network_host(h);
+ 
+       config data;
+       network::connection data_res = 
gui::network_data_dialog(disp,_("Connecting to remote host..."),data);
+       mp::check_response(data_res, data);
+
+       const std::string& version = data["version"];
+       if(version.empty() == false && version != game_config::version) {
+               throw network::error("The server requires version '" + version
+                     + "' while you are using version '" + 
game_config::version + "'");
+       }
+
+       //if we got a direction to login
+       if(data.child("mustlogin")) {
+
+               bool first_time = true;
+               config* error = NULL;
+
+               do {
+                       if(error != NULL) {
+                               
gui::show_dialog(disp,NULL,"",(*error)["message"],gui::OK_ONLY);
+                       }
 
-       regenerate_map_->set_location(rect.x,rect.y);
+                       std::string login = preferences::login();
 
-       rect.y += regenerate_map_->location().h + border_size;
+                       if(!first_time) {       
+                               const int res = gui::show_dialog(disp, NULL, "",
+                                               _("You must log in to this 
server"), gui::OK_CANCEL,
+                                               NULL, NULL, _("Login") + 
std::string(": "), &login);
+                               if(res != 0 || login.empty()) {
+                                       return ABORT_SERVER;
+                               }
 
-       generator_settings_->set_location(rect.x,rect.y);
+                               preferences::set_login(login);
+                       }
 
-       //player amount number background
-       SDL_Rect player_num_rect = {xpos+minimap_width/2 - 
30,ypos+minimap_width,100,25};
-       playernum_restorer_ = surface_restorer(&disp_.video(),player_num_rect);
+                       first_time = false;
 
-       SDL_Rect era_rect = {xpos,player_num_rect.y+player_num_rect.h + 
border_size,50,20};
-       era_rect = 
font::draw_text(&disp_,era_rect,font::SIZE_SMALL,font::GOOD_COLOUR,_("Era:"),
-                                  era_rect.x,era_rect.y);
+                       config response;
+                       response.add_child("login")["username"] = login;
+                       network::send_data(response);
        
-       era_combo_->set_location(era_rect.x+era_rect.w+border_size,era_rect.y);
+                       data_res = network::receive_data(data, 0, 3000);
+                       if(!data_res) {
+                               throw network::error(_("Connection timed out"));
+                       }
 
-       SDL_Rect minimap_rect = {xpos,ypos,minimap_width,minimap_width};
-       minimap_restorer_ = surface_restorer(&disp_.video(),minimap_rect);
+                       LOG_NW << "login response: '" << data.write() << "'\n";
 
-       name_entry_->hide(false);
-       maps_menu_->hide(false);
-       turns_slider_->hide(false);
-       village_gold_slider_->hide(false);
-       xp_modifier_slider_->hide(false);
-       fog_game_->hide(false);
-       shroud_game_->hide(false);
-       observers_game_->hide(false);
-       vision_combo_->hide(false);
-       right_button->hide(false);
-       left_button->hide(false);
-       regenerate_map_->hide(false);
-       generator_settings_->hide(false);
-       era_combo_->hide(false);
+                       error = data.child("error");
+               } while(error != NULL);
+       }
 
-       LOG_DP << "setup dialog end set_area\n";
-}
+       if (data.child("join_lobby")) {
+               return WESNOTHD_SERVER;
+       } else {
+               return SIMPLE_SERVER;
+       }
 
-void multiplayer_game_setup_dialog::clear_area()
-{
-       name_entry_->hide();
-       maps_menu_->hide();
-       turns_slider_->hide();
-       village_gold_slider_->hide();
-       xp_modifier_slider_->hide();
-       fog_game_->hide();
-       shroud_game_->hide();
-       observers_game_->hide();
-       vision_combo_->hide();
-       launch_game_->hide();
-       cancel_game_->hide();
-       regenerate_map_->hide();
-       generator_settings_->hide();
-       era_combo_->hide();
 }
 
-lobby::RESULT multiplayer_game_setup_dialog::process()
-{
-       CKey key;
-
-       name_entry_->process();
-       maps_menu_->process();
 
-       if(cancel_game_->pressed() || key[SDLK_ESCAPE]) 
-               return lobby::QUIT;
+// The multiplayer logic consists in 4 screens:
+//
+// lobby <-> create <-> connect <-> (game)
+//       <------------> wait    <-> (game)
+//
+// To each of this screen corresponds a dialog, each dialog being defined in
+// the multiplayer_(screen) file.
+//
+// The functions enter_(screen)_mode are simple functions that take care of
+// creating the dialogs, then, according to the dialog result, of calling other
+// of those screen functions.
 
-       if(launch_game_->pressed() || maps_menu_->double_clicked()) {
-               if (!name_entry_->text().empty())
-                       return lobby::CREATE;
-               else
-                       gui::show_dialog(disp_, NULL, "", _("You must enter a 
name."), gui::OK_ONLY);
-       }
-
-       events::raise_process_event();
-       events::raise_draw_event();
-       SDL_Rect const &screen_area = disp_.screen_area();
-       display *disp = &disp_;
-
-       //Turns per game
-       {
-               const int cur_turns = turns_slider_->value();
-               turns_restorer_.restore();
-
-               std::stringstream turns_str;
-               turns_str << _("Turns: ");
-               if (cur_turns < 100)
-                       turns_str << cur_turns;
-               else
-                       turns_str << _("unlimited");
-
-               SDL_Rect const &rect = turns_restorer_.area();
-               font::draw_text(disp, screen_area, font::SIZE_SMALL, 
font::GOOD_COLOUR,
-                               turns_str.str(), rect.x, rect.y);
-       }
+void enter_wait_mode(display& disp, const config& game_config, game_data& 
data, mp::chat& chat, config& gamelist, bool observe)
+{
+       mp::ui::result res;
+       config level;
+       game_state state;
+       network_game_manager m;
 
-       //Villages can produce between 1 and 10 gold a turn
        {
-               const int village_gold = village_gold_slider_->value();
-               village_gold_restorer_.restore();
+               mp::wait ui(disp, game_config, data, chat, gamelist);
+               
+               ui.join_game(observe);
 
-               std::stringstream gold_str;
-               gold_str << _("Village Gold: ") << village_gold;
+               run_lobby_loop(disp, ui);
+               res = ui.get_result();
 
-               SDL_Rect const &rect = village_gold_restorer_.area();
-               font::draw_text(disp, screen_area, font::SIZE_SMALL, 
font::GOOD_COLOUR,
-                               gold_str.str(), rect.x, rect.y);
+               if (res == mp::ui::PLAY) {
+                       ui.start_game();
+                       level = ui.get_level();
+                       state = ui.get_state();
+               }
        }
 
-       //Experience modifier
-       {
-               const int xpmod = xp_modifier_slider_->value();
-               xp_restorer_.restore();
-
-               std::stringstream xp_str;
-               xp_str << _("Experience Requirements: ") << xpmod << '%';
-
-               SDL_Rect const &rect = xp_restorer_.area();
-               font::draw_text(disp, screen_area, font::SIZE_SMALL, 
font::GOOD_COLOUR,
-                               xp_str.str(), rect.x, rect.y);
+       switch (res) {
+       case mp::ui::PLAY:
+               play_level(data, game_config, &level, disp.video(), state, 
std::vector<config*>());
+               recorder.clear();
+
+               break;
+       case mp::ui::QUIT:
+       default:
+               break;
        }
+}
 
-       bool map_changed = map_selection_ != maps_menu_->selection();
-       map_selection_ = maps_menu_->selection();
-
-       if(map_changed) {
-               generator_.assign(NULL);
-
-               SDL_Rect minimap_rect = minimap_restorer_.area();
-               tooltips::clear_tooltips(minimap_rect);
-
-               const size_t select = size_t(maps_menu_->selection());
-
-               if(select < user_maps_.size()) {
-                       const config* const generic_multiplayer = 
cfg_.child("generic_multiplayer");
-                       if(generic_multiplayer != NULL) {
-                               scenario_data_ = *generic_multiplayer;
-                               scenario_data_["map_data"] = 
read_map(user_maps_[select]);
-                               level_ = &scenario_data_;
-                       }
-
-               } else if(select != maps_menu_->nitems()-1) {
-                       const size_t index = select - user_maps_.size();
-                       const config::child_list& levels = 
cfg_.get_children("multiplayer");
-
-                       if(index < levels.size()) {
-
-                               scenario_data_ = *levels[index];
-                               level_ = &scenario_data_;
-
-                               std::string& map_data = 
scenario_data_["map_data"];
-                               if (map_data.empty() && 
!scenario_data_["map"].empty()) {
-                                       map_data = 
read_map(scenario_data_["map"]);
-                               }
-
-                               //if the map should be randomly generated
-                               if (!scenario_data_["map_generation"].empty()) {
-                                       
generator_.assign(create_map_generator(scenario_data_["map_generation"],
-                                                         
scenario_data_.child("generator")));
-                               }
-
-                               if (!scenario_data_["description"].empty()) {
-                                       
tooltips::add_tooltip(minimap_rect,scenario_data_["description"]);
-                               }
-                       }
-               } else {
+void enter_connect_mode(display& disp, const config& game_config, game_data& 
data, 
+               mp::chat& chat, config& gamelist, const mp::create::parameters& 
params,
+               mp::controller default_controller, bool is_server)
+{
+       mp::ui::result res;
+       config level;
+       game_state state;
+       const network::manager net_manager;
+       const network::server_manager serv_manager(15000, is_server ? 
+                       network::server_manager::TRY_CREATE_SERVER :
+                       network::server_manager::NO_SERVER);
+       network_game_manager m;
 
-                       scenario_data_.clear();
+       {
+               mp::connect ui(disp, game_config, data, chat, gamelist, params, 
default_controller);
+               run_lobby_loop(disp, ui);
 
-                       playernum_restorer_.restore();
-                       minimap_restorer_.restore();
+               res = ui.get_result();
 
-                       SDL_Rect const &rect = playernum_restorer_.area();
-                       font::draw_text(disp, screen_area, font::SIZE_SMALL, 
font::GOOD_COLOUR,
-                                       _("Players: ") + std::string(1, '?'), 
rect.x, rect.y);
+               // start_game() updates the parameters to reflect game start,
+               // so it must be called before get_level() 
+               if (res == mp::ui::PLAY) {
+                       ui.start_game();
+                       level = ui.get_level();
+                       state = ui.get_state();
                }
        }
 
-       if(generator_ != NULL && generator_->allow_user_config() && 
generator_settings_->pressed()) {
-               generator_->user_config(disp_);
-               map_changed = true;
+       switch (res) {
+       case mp::ui::PLAY:
+               play_level(data, game_config, &level, disp.video(), state, 
std::vector<config*>());
+               recorder.clear();
+
+               break;
+       case mp::ui::QUIT:
+       default:
+               break;
        }
+}
 
-       if(generator_ != NULL && level_ != NULL && (map_changed || 
regenerate_map_->pressed())) {
-               const cursor::setter cursor_setter(cursor::WAIT);
-
-               //generate the random map
-               scenario_data_ = 
generator_->create_scenario(std::vector<std::string>());
-               level_ = &scenario_data_;
-               map_changed = true;
+void enter_create_mode(display& disp, const config& game_config, game_data& 
data, mp::chat& chat, config& gamelist, mp::controller default_controller, bool 
is_server)
+{
+       mp::ui::result res;
+       mp::create::parameters params;
 
-               //set the scenario to have placing of sides based on the 
terrain they prefer
-               (*level_)["modify_placing"] = "true";
+       {
+               mp::create ui(disp, game_config, chat, gamelist);
+               run_lobby_loop(disp, ui);
+               res = ui.get_result();
+               params = ui.get_parameters();
        }
 
-       //if the map has changed and "Load Map" is not selected
-       if(map_changed && level_ != NULL) {
-               generator_settings_->hide(generator_ == NULL);
-               regenerate_map_->hide(generator_ == NULL);
-
-               const std::string& map_data = (*level_)["map_data"];
-
-               gamemap map(cfg_,map_data);
+       switch (res) {
+       case mp::ui::CREATE:
+               enter_connect_mode(disp, game_config, data, chat, gamelist, 
params, default_controller, is_server);
+               break;
+       case mp::ui::QUIT:
+       default:
+               break;
+       }
+}
 
-               //if there are less sides in the configuration than there are 
starting
-               //positions, then generate the additional sides
-               const int map_positions = map.num_valid_starting_positions();
+void enter_lobby_mode(display& disp, const config& game_config, game_data& 
data, mp::chat& chat, config& gamelist) 
+{
+       mp::ui::result res;
 
-               for(int pos = level_->get_children("side").size(); pos < 
map_positions; ++pos) {
-                       config& side = level_->add_child("side");
-                       side["enemy"] = "1";
-                       char buf[50];
-                       sprintf(buf,"%d",(pos+1));
-                       side["side"] = buf;
-                       side["team_name"] = buf;
-                       side["canrecruit"] = "1";
-                       side["controller"] = "human";
+       while (true) {
+               {
+                       mp::lobby ui(disp, game_config, chat, gamelist);
+                       run_lobby_loop(disp, ui);
+                       res = ui.get_result();
                }
 
-               //if there are too many sides, remove some
-               while(level_->get_children("side").size() > map_positions) {
-                       
level_->remove_child("side",level_->get_children("side").size()-1);
+               switch (res) {
+               case mp::ui::JOIN:
+                       enter_wait_mode(disp, game_config, data, chat, 
gamelist, false);
+                       break;
+               case mp::ui::OBSERVE:
+                       enter_wait_mode(disp, game_config, data, chat, 
gamelist, true);
+                       break;
+               case mp::ui::CREATE:
+                       try {
+                               enter_create_mode(disp, game_config, data, 
chat, gamelist, mp::CNTR_NETWORK, false);
+                       } catch(network::error& error) {
+                               if (!error.message.empty())
+                                       gui::show_error_message(disp, 
error.message);
+                       }
+                       break;
+               case mp::ui::QUIT:
+               default:
+                       return;
                }
+       }
+}
+ 
+}
 
-               SDL_Rect minimap_rect = minimap_restorer_.area();
-               const surface mini(image::getMinimap(minimap_rect.w, 
minimap_rect.h, map, 0));
+namespace mp {
 
-               if(mini != NULL) {
-                       SDL_BlitSurface(mini, NULL, disp_.video().getSurface(), 
&minimap_rect);
-                       update_rect(minimap_rect);
-               
-                       //Display the number of players
-                       const int nsides = level_->get_children("side").size();
-                       playernum_restorer_.restore();
-
-                       std::stringstream players;
-                       players << _("Players: ") << nsides;
-
-                       SDL_Rect const &rect = playernum_restorer_.area();
-                       font::draw_text(disp, screen_area, font::SIZE_SMALL, 
font::GOOD_COLOUR,
-                                       players.str(), rect.x, rect.y);
-               }
-       }
+void start_server(display& disp, const config& game_config, game_data& data,
+               mp::controller default_controller, bool is_server)
+{
+       mp::chat chat;
+       config gamelist;
+       preferences::display_manager disp_manager(&disp);
 
-       return lobby::CONTINUE;
+       enter_create_mode(disp, game_config, data, chat, gamelist, 
default_controller, is_server);
 }
 
-void multiplayer_game_setup_dialog::start_game()
+void start_client(display& disp, const config& game_config, game_data& data,
+               const std::string host)
 {
-       LOG_G << "calling start_game()\n";
        const network::manager net_manager;
-       const network::server_manager server_man(15000,server_ ? 
network::server_manager::TRY_CREATE_SERVER : 
network::server_manager::NO_SERVER);
-
-       if(server_ && server_man.is_running() == false) {
-               gui::show_dialog(disp_,NULL,_("Warning"),_("The game was unable 
to bind to the port needed to host games over the network. Network players will 
be unable to connect to this game"),
-                                gui::OK_ONLY);
-       }
-
-       turns_restorer_ = surface_restorer();
-       village_gold_restorer_ = surface_restorer();
-       xp_restorer_ = surface_restorer();
-       playernum_restorer_ = surface_restorer();
-       minimap_restorer_ = surface_restorer();
-
-       std::cerr << "loading connector...\n";
-       //Connector
-       mp_connect connector(disp_, name_entry_->text(), cfg_, units_data_, 
state_, false, controller_);
+       preferences::display_manager disp_manager(&disp);
 
-       std::cerr << "done loading connector...\n";
-
-       const int turns = turns_slider_->value() < turns_slider_->max_value() ?
-               turns_slider_->value() : -1;
-
-       const config::child_list& era_list = cfg_.get_children("era");
-
-       const int share = vision_combo_->selected();
-
-       //Save values for next game
-       preferences::set_allow_observers(observers_game_->checked());
-       preferences::set_fog(fog_game_->checked());
-       preferences::set_shroud(shroud_game_->checked());
-       preferences::set_turns(turns_slider_->value());
-       preferences::set_village_gold(village_gold_slider_->value());
-       preferences::set_xp_modifier(xp_modifier_slider_->value());
-       preferences::set_era(era_combo_->selected());
-       preferences::set_map(maps_menu_->selection());
-       
-       const int res = 
connector.load_map((*era_list[era_combo_->selected()])["id"],
-                          scenario_data_, turns, village_gold_slider_->value(),
-                                          xp_modifier_slider_->value(), 
fog_game_->checked(),
-                                          shroud_game_->checked(), 
observers_game_->checked(),
-                                          share == 0, share == 1);
-       if(res == -1) {
-               return;
-       }
-
-       name_entry_->set_focus(false);
-
-       //free up widget resources so they're not consumed while the game is on
-       maps_menu_.assign(NULL);
-       turns_slider_.assign(NULL);
-       village_gold_slider_.assign(NULL);
-       xp_modifier_slider_.assign(NULL);
-       fog_game_.assign(NULL);
-       shroud_game_.assign(NULL);
-       observers_game_.assign(NULL);
-       vision_combo_.assign(NULL);
-       cancel_game_.assign(NULL);
-       launch_game_.assign(NULL);
-       regenerate_map_.assign(NULL);
-       generator_settings_.assign(NULL);
-       era_combo_.assign(NULL);
-       name_entry_.assign(NULL);
-       generator_.assign(NULL);
-
-       std::vector<std::string> messages;
-       config game_data;
-       lobby::RESULT result = lobby::CONTINUE;
-       while(result == lobby::CONTINUE) {
-               result = lobby::enter(disp_,game_data,cfg_,&connector,messages);
+       mp::chat chat;
+       config gamelist;
+       server_type type = open_connection(disp, host);
+
+       switch(type) {
+       case WESNOTHD_SERVER:
+               enter_lobby_mode(disp, game_config, data, chat, gamelist);
+               break;
+       case SIMPLE_SERVER:
+               enter_wait_mode(disp, game_config, data, chat, gamelist, false);
+               break;
+       case ABORT_SERVER:
+               break;
        }
+}
 
-       if(result == lobby::CREATE) {
-               connector.start_game();
-       }
 }
+
Index: wesnoth/src/multiplayer.hpp
diff -u wesnoth/src/multiplayer.hpp:1.24 wesnoth/src/multiplayer.hpp:1.25
--- wesnoth/src/multiplayer.hpp:1.24    Mon Nov  1 18:06:36 2004
+++ wesnoth/src/multiplayer.hpp Sun Feb 20 22:30:27 2005
@@ -1,7 +1,7 @@
-/* $Id: multiplayer.hpp,v 1.24 2004/11/01 18:06:36 gruikya Exp $ */
+/* $Id: multiplayer.hpp,v 1.25 2005/02/20 22:30:27 gruikya Exp $ */
 /*
-   Copyright (C) 2003 by David White <address@hidden>
-   Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
+   Copyright (C)
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License.
@@ -13,79 +13,23 @@
 #ifndef MULTIPLAYER_HPP_INCLUDED
 #define MULTIPLAYER_HPP_INCLUDED
 
-#include "config.hpp"
 #include "display.hpp"
-#include "font.hpp"
-#include "gamestatus.hpp"
-#include "mapgen.hpp"
-#include "multiplayer_lobby.hpp"
-#include "scoped_resource.hpp"
+#include "config.hpp"
 #include "unit_types.hpp"
-#include "video.hpp"
 
-#include "widgets/button.hpp"
-#include "widgets/combo.hpp"
-#include "widgets/menu.hpp"
-#include "widgets/slider.hpp"
-#include "widgets/textbox.hpp"
-
-//an object which guarantees that when it is destroyed, a 'leave game'
-//message will be sent to any hosts still connected.
-struct network_game_manager {
-       network_game_manager() {}
-       ~network_game_manager();
-};
-
-class multiplayer_game_setup_dialog : public lobby::dialog, public 
font::floating_label_context
-{
-public:
-       multiplayer_game_setup_dialog(display& disp, game_data& units_data,
-                      const config& cfg, game_state& state, bool server=false, 
const std::string& controller="ai");
-
-       virtual void set_area(const SDL_Rect& area);
-       virtual void clear_area();
-
-       lobby::RESULT process();
-
-       void start_game();
-
-private:
-       display& disp_;
-       game_data& units_data_;
-       const config& cfg_;
-       game_state& state_;
-       bool server_;
-       SDL_Rect area_;
-
-       config* level_;
-
-       int map_selection_;
-
-       std::vector<std::string> user_maps_, map_options_;
-       config scenario_data_;
-
-       util::scoped_ptr<gui::menu> maps_menu_;
-       util::scoped_ptr<gui::slider> turns_slider_, village_gold_slider_, 
xp_modifier_slider_;
-       util::scoped_ptr<gui::button> fog_game_, shroud_game_, observers_game_,
-                                     cancel_game_, launch_game_,
-                                     regenerate_map_, generator_settings_;
-
-       util::scoped_ptr<gui::combo> era_combo_, vision_combo_;
-       util::scoped_ptr<gui::textbox> name_entry_;
-
-       util::scoped_ptr<map_generator> generator_;
-
-       surface_restorer turns_restorer_, village_gold_restorer_, xp_restorer_, 
playernum_restorer_,
-                        minimap_restorer_;
-
-       const std::string controller_;
-};
-
-//function to host a multiplayer game. If server is true, then the
-//game will accept connections from foreign hosts. Otherwise it'll
-//just use existing network connections for players, or the game
-//is an entirely local game
-int play_multiplayer(display& disp, game_data& units_data,
-                      const config& cfg, game_state& state, bool server=true);
+namespace mp {
+       
+enum controller { CNTR_NETWORK = 0, CNTR_LOCAL, CNTR_COMPUTER, CNTR_EMPTY, 
CNTR_LAST };
+
+/**
+ * This is the main entry points of multiplayer mode.
+ */
+void start_server(display& disp, const config& game_config, game_data& data,
+               mp::controller default_controller, bool is_server);
+
+void start_client(display& disp, const config& game_config, game_data& data, 
+               const std::string host);
+
+}
 
 #endif
Index: wesnoth/src/multiplayer_connect.cpp
diff -u wesnoth/src/multiplayer_connect.cpp:1.103 
wesnoth/src/multiplayer_connect.cpp:1.104
--- wesnoth/src/multiplayer_connect.cpp:1.103   Sun Feb 20 21:45:21 2005
+++ wesnoth/src/multiplayer_connect.cpp Sun Feb 20 22:30:27 2005
@@ -1,7 +1,7 @@
-/* $Id: multiplayer_connect.cpp,v 1.103 2005/02/20 21:45:21 silene Exp $ */
+/* $Id: multiplayer_connect.cpp,v 1.104 2005/02/20 22:30:27 gruikya Exp $ */
 /*
-   Copyright (C) 2003 by David White <address@hidden>
-   Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
+   Copyright (C) 
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License.
@@ -11,1084 +11,1005 @@
    See the COPYING file for more details.
 */
 
-#include "global.hpp"
-
-#include "events.hpp"
-#include "font.hpp"
-#include "language.hpp"
-#include "log.hpp"
-#include "image.hpp"
-#include "mapgen.hpp"
-#include "multiplayer.hpp"
-#include "multiplayer_client.hpp"
 #include "multiplayer_connect.hpp"
-#include "network.hpp"
-#include "playlevel.hpp"
+#include "font.hpp"
 #include "preferences.hpp"
-#include "replay.hpp"
 #include "show_dialog.hpp"
-#include "util.hpp"
+#include "dialogs.hpp"
+#include "game_config.hpp"
 #include "wassert.hpp"
-#include "widgets/textbox.hpp"
-#include "widgets/button.hpp"
-#include "widgets/combo.hpp"
-#include "widgets/menu.hpp"
-#include "widgets/slider.hpp"
-
-#include <sstream>
-#include <string>
-#include <vector>
 
-#define ERR_CF lg::err(lg::config)
-#define LOG_CF lg::info(lg::config)
-#define ERR_NW lg::err(lg::network)
 #define LOG_NW lg::info(lg::network)
-#define LOG_G lg::info(lg::general)
+#define ERR_NW lg::err(lg::network)
+#define LOG_CF lg::info(lg::config)
+#define ERR_CF lg::err(lg::config)
 
-mp_connect::mp_connect(display& disp, std::string game_name,
-                      const config &cfg, game_data& data, game_state& state,
-                      bool join, const std::string& default_controller) : 
-           disp_(&disp), cfg_(&cfg), data_(&data), state_(&state),
-           show_replay_(false), save_(false), join_(join),
-           scroll_pane_(disp),
-           ai_(disp, _(" Computer vs Computer ")),
-           launch_(disp, _("I'm Ready")),
-           cancel_(disp, _("Cancel")),
-           waiting_label_(disp, ""),
-           message_full_(true), default_controller_(default_controller),
-           team_prefix_(_("Team") + std::string(" "))
-{
-       // Send Initial information
-       config response;
-       config& create_game = response.add_child("create_game");
-       create_game["name"] = game_name;
-       network::send_data(response);
+namespace {
+       const char* controller_names[] = {
+               "network",
+               "human",
+               "ai",
+               "null"
+       };
+}
+
+namespace mp {
+
+connect::side::side(connect& parent, const config& cfg, int index, int 
default_gold,
+               bool enabled) :
+       parent_(&parent),
+
+       cfg_(cfg),
+
+       index_(index),
+       controller_(parent_->default_controller_),
+
+       player_number_(parent.disp(), 
lexical_cast_default<std::string>(index+1, ""),
+                       font::SIZE_XLARGE, font::GOOD_COLOUR),
+       combo_controller_(parent.disp(), parent.player_types_),
+       orig_controller_(parent.disp(), cfg["description"], font::SIZE_SMALL), 
+       combo_faction_(parent.disp(), parent.player_factions_),
+       combo_leader_(parent.disp(), std::vector<std::string>()),
+       combo_team_(parent.disp(), parent.player_teams_),
+       combo_colour_(parent.disp(), parent.player_colours_),
+       slider_gold_(parent.disp()),
+       label_gold_(parent.disp(), "100", font::SIZE_NORMAL, font::GOOD_COLOUR),
+
+       llm_(parent.era_sides_, &parent.game_data_, &combo_leader_),
+
+       enabled_(enabled),
+       changed_(false)
+{
+       SDL_Rect r;
+       r.w = 64;
+       r.h = 16;
+
+       slider_gold_.set_min(20);
+       slider_gold_.set_max(1000);
+       slider_gold_.set_increment(25);
+       slider_gold_.set_value(lexical_cast_default<int>(cfg_["gold"], 
default_gold));
+       slider_gold_.set_location(r);
+
+       combo_faction_.enable(enabled_);
+       combo_leader_.enable(enabled_);
+       combo_team_.enable(enabled_);
+       combo_colour_.enable(enabled_);
+       slider_gold_.hide(!enabled_);
+
+       id_ = ""; // Id is reset, and not imported from loading savegames
+       original_description_ = cfg_["description"];
+       faction_ = lexical_cast_default<int>(cfg_["team"], 0);
+       team_ = lexical_cast_default<int>(cfg_["team"], index_);
+       colour_ = lexical_cast_default<int>(cfg_["colour"], index_);
+       gold_ = lexical_cast_default<int>(cfg_["gold"], default_gold);
+
+       // "Faction name" hack
+       if (!enabled_) {
+               faction_ = 0;
+               std::vector<std::string> pseudo_factions;
+               pseudo_factions.push_back(cfg_["name"]);
+               combo_faction_.set_items(pseudo_factions);
+               combo_faction_.set_selected(0);
+       }
+
+       update_ui();
+}
+
+connect::side::side(const side& a) :
+       parent_(a.parent_), cfg_(a.cfg_), 
+       index_(a.index_), id_(a.id_), 
original_description_(a.original_description_),
+       controller_(a.controller_),
+       faction_(a.faction_), team_(a.team_), colour_(a.colour_),
+       gold_(a.gold_), leader_(a.leader_), /* taken_(a.taken_), */
+       player_number_(a.player_number_), 
combo_controller_(a.combo_controller_),
+       orig_controller_(a.orig_controller_),
+       combo_faction_(a.combo_faction_), combo_leader_(a.combo_leader_),
+       combo_team_(a.combo_team_), combo_colour_(a.combo_colour_),
+       slider_gold_(a.slider_gold_), label_gold_(a.label_gold_), llm_(a.llm_),
+       enabled_(a.enabled_), changed_(a.changed_)
+{
+       llm_.set_combo(&combo_leader_);
+}
+
+void connect::side::add_widgets_to_scrollpane(gui::scrollpane& pane, int pos)
+{ 
+       pane.add_widget(&player_number_, 10, 3 + pos);
+       pane.add_widget(&combo_controller_, 30, 5 + pos);
+       pane.add_widget(&orig_controller_, 30 + (combo_controller_.width() - 
orig_controller_.width()) / 2, 35 + pos + (combo_leader_.height() - 
orig_controller_.height()) / 2);
+       pane.add_widget(&combo_faction_, 145, 5 + pos);
+       pane.add_widget(&combo_leader_, 145, 35 + pos);
+       pane.add_widget(&combo_team_, 260, 5 + pos);
+       pane.add_widget(&combo_colour_, 375, 5 + pos);
+       pane.add_widget(&slider_gold_, 490, 5 + pos);
+       pane.add_widget(&label_gold_, 500 + slider_gold_.width(), 5 + pos);
+}
+
+void connect::side::process_event()
+{
+       if(combo_controller_.changed() && combo_controller_.selected() >= 0) {
+               if (combo_controller_.selected() == CNTR_LAST) {
+                       update_controller_ui();
+               } else if (combo_controller_.selected() < CNTR_LAST) {
+                       // If the current side corresponds to an existing user,
+                       // we must kick it!
+                       
+                       if(id_ == preferences::login()) {
+                               update_controller_ui(); // Cannot kick game 
creator
+                       } else {
+                               // Update controller first, or else kick will 
reset it.
+                               controller_ = 
mp::controller(combo_controller_.selected());
+                               if(!id_.empty()) {
+                                       parent_->kick_player(id_);
+                               }
+                               id_ = "";
+                               changed_ = true;
+                       }
+               } else {
+                       size_t user = combo_controller_.selected() - CNTR_LAST 
- 1;
 
-}
+                       // If the selected user already was attributed to
+                       // another side, find its side, and switch users.
+                       const std::string new_id = parent_->users_[user].name;
+                       if (new_id != id_) {
+                               int old_side = 
parent_->find_player_side(new_id);
+                               if (old_side != -1) {
+                                       if (id_.empty()) {
+                                               
parent_->sides_[old_side].set_controller(controller_);
+                                       } else {
+                                               
parent_->sides_[old_side].set_id(id_);
+                                       }
+                               }
+                               id_ = new_id;
+                               controller_ = parent_->users_[user].controller;
+                               changed_ = true;
+                       }
+               }
+       }
 
-mp_connect::~mp_connect()
-{
-       if(network::nconnections() > 0) {
-               config cfg;
-               cfg.add_child("leave_game");
-               network::send_data(cfg);
+       if(!enabled_)
+               return; 
+
+       if (combo_faction_.changed() && combo_faction_.selected() >= 0) {
+               faction_ = combo_faction_.selected();
+               llm_.update_leader_list(faction_);
+               changed_ = true;
+       }
+       if (combo_leader_.changed() && combo_leader_.selected() >= 0) {
+               changed_ = true;
+       }
+       if (combo_team_.changed() && combo_team_.selected() >= 0) {
+               team_ = combo_team_.selected();
+               changed_ = true;
+       }
+       if (combo_colour_.changed() && combo_colour_.selected() >= 0) {
+               colour_ = combo_colour_.selected();
+               changed_ = true;
+       }
+       if (slider_gold_.value() != gold_) {
+               gold_ = slider_gold_.value();
+               label_gold_.set_text(lexical_cast_default<std::string>(gold_, 
"0"));
+               changed_ = true;
        }
 }
 
-int mp_connect::load_map(const std::string& era, config& scenario_data, int 
num_turns, int village_gold, int xpmodifier,
-                         bool fog_game, bool shroud_game, bool 
allow_observers, bool share_view, bool share_maps)
+bool connect::side::changed()
 {
-       log_scope("load_map");
-       // Setup the game
-       config* level_ptr;
-
-       if(scenario_data.child("side") == NULL) {
-               //Load a saved game
-               save_ = true;
-               bool show_replay = false;
-               const std::string game = dialogs::load_game_dialog(*disp_, 
*cfg_, *data_, &show_replay);
-               if(game == "") {
-                       return -1;
-               }
+       bool res = changed_;
+       changed_ = false;
+       return res;
+}
 
-               log_scope("loading save");
+bool connect::side::available() const
+{
+       return controller_ == CNTR_NETWORK && id_.empty();
+}
 
-               state_->players.clear();
-               load_game(*data_, game, *state_);
+void connect::side::update_controller_ui()
+{
+       if (id_.empty()) {
+               combo_controller_.set_selected(controller_);
+       } else {
+               connected_user_list::iterator player = 
parent_->find_player(id_);
 
-               if(state_->campaign_type != "multiplayer") {
-                       gui::show_dialog(*disp_, NULL, "", 
-                                        _("This is not a multiplayer save"),
-                                        gui::OK_ONLY);
-                       return -1;
+               if (player != parent_->users_.end()) {
+                       combo_controller_.set_selected(CNTR_LAST + 1 + (player 
- parent_->users_.begin()));
+               } else {
+                       combo_controller_.set_selected(CNTR_NETWORK);
                }
+       }
 
-               if(state_->version != game_config::version) {
-                       const int res = gui::show_dialog(*disp_, NULL, "",
-                                               _("This save is from a 
different version of the game. Do you want to try to load it?"),
-                                               gui::YES_NO);
-                       if(res == 1) {
-                               return -1;
-                       }
-               }
+}
 
-               scenario_data = state_->snapshot;
-               level_ptr = &scenario_data;
+void connect::side::update_ui()
+{
+       update_controller_ui();
 
-               //make all sides untaken
-               for(config::child_itors j = level_ptr->child_range("side"); 
j.first != j.second; ++j.first) {
-                       (**j.first)["taken"] = "";
+       if (combo_faction_.selected() != faction_ && combo_faction_.selected() 
>= 0) {
+               combo_faction_.set_selected(faction_);
+       }
 
-                       //tell clients not to change their race
-                       (**j.first)["allow_changes"] = "no";
-               }
+       combo_team_.set_selected(team_);
+       combo_colour_.set_selected(colour_);
+       slider_gold_.set_value(gold_);
+       label_gold_.set_text(lexical_cast_default<std::string>(gold_, "0"));
+}
 
-               recorder = replay(state_->replay_data);
+config connect::side::get_config() const
+{
+       config res = cfg_;
 
-               config* const start = level_ptr->child("start");
+       // If the user is allowed to change type, faction, leader etc, then
+       // import their new values in the config.
+       if(enabled_) {
+               // Merge the faction data to res
+               res.append(*(parent_->era_sides_[faction_]));
+       }
+       
+       res["controller"] = controller_names[controller_];
+       res["id"] = id_;
+       if (id_.empty()) {
+               switch(controller_) {
+               case CNTR_NETWORK:
+                       res["description"] = _("(Vacant slot)");
+                       break;
+               case CNTR_LOCAL:
+                       res["description"] = _("Anonymous local player");
+                       break;
+               case CNTR_COMPUTER:
+                       res["description"] = _("Computer player");
+                       break;
+               case CNTR_EMPTY:
+                       res["description"] = _("(Empty slot)");
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               res["description"] = id_;
+       }
+       res["original_description"] = original_description_;
 
-               //if this is a snapshot save, we don't want to use the replay 
data
-               if(scenario_data["snapshot"] == "yes") {
-                       if(start != NULL)
-                               start->clear_children("replay");
-                       level_ptr->clear_children("replay");
-                       recorder.set_to_end();
+       if(enabled_) {
+               if (leader_.empty()) {
+                       res["type"] = llm_.get_leader();
                } else {
-                       //add the replay data under the level data so clients 
can
-                       //receive it
-                       level_ptr->clear_children("replay");
-                       level_ptr->add_child("replay") = state_->replay_data;
+                       res["type"] = leader_;
                }
+               res["team"] = lexical_cast<std::string>(team_);
+               res["colour"] = lexical_cast<std::string>(colour_);
+               res["gold"] = lexical_cast<std::string>(gold_);
 
+               res["allow_changes"] = "yes";
        } else {
-               //Load a new map
-               save_ = false;
-               level_ptr = &scenario_data;
-
-               //set the number of turns here
-               std::stringstream turns;
-               turns << num_turns;
-               (*level_ptr)["turns"] = turns.str();
-       }
-
-       wassert(level_ptr != NULL);
-
-       if(scenario_data["era"].empty()) {
-               era_ = era;
-       } else { 
-               era_ = scenario_data["era"];
+               res["allow_changes"] = "no";
        }
 
-       //this will force connecting clients to be using the same version 
number as us.
-       (*level_ptr)["version"] = game_config::version;
+       return res;
+}
 
-       level_ = level_ptr;
-       state_->label = level_->values["name"];
-       state_->players.clear();
+void connect::side::set_controller(mp::controller controller)
+{
+       controller_ = controller;
+       id_ = "";
 
-       state_->scenario = scenario_data["id"];
+       update_ui();
+}
 
-       level_->values["observer"] = allow_observers ? "yes" : "no";
+mp::controller connect::side::get_controller() const
+{
+       return controller_;
+}
 
-       const config::child_itors sides = level_->child_range("side");
+void connect::side::update_user_list()
+{
+       bool name_present = false;
 
-       const config* const era_cfg = cfg_->find_child("era","id",era_);
+       std::vector<std::string> list = parent_->player_types_;
+       list.push_back("----");
 
-       if(era_cfg == NULL) {
-               ERR_CF << "era '" << era_ << "' not found\n";
-               return -1;
+       connected_user_list::const_iterator itor;
+       for (itor = parent_->users_.begin(); itor != parent_->users_.end();
+                       ++itor) {
+               list.push_back(itor->name);
+               if (itor->name == id_)
+                       name_present = true;
        }
 
-       const config::child_list& possible_sides = 
era_cfg->get_children("multiplayer_side");
-
-       if(sides.first == sides.second || possible_sides.empty()) {
-               gui::show_dialog(*disp_, NULL, "", 
-                                _("No multiplayer sides."),
-                                gui::OK_ONLY);
-               ERR_CF << "no multiplayer sides found\n";
-               return -1;
+       if (name_present == false) {
+               id_ = "";
        }
 
-       config::child_iterator sd;
-
-       bool first = true;
-       for(sd = sides.first; sd != sides.second; ++sd) {
-               config& side = (**sd);
-
-               if(save_ == false)
-               {
-                       std::stringstream svillage_gold;
-                       svillage_gold << village_gold;
-                       side["village_gold"] = svillage_gold.str();
-                       side["gold"] = "100";
-                       if (first == true) {
-                               (**sd)["controller"] = "human";
-                               (**sd)["description"] = preferences::login();
-                               first = false;
-                       } else {
-                               (**sd)["controller"] = default_controller_;
-                               (**sd)["description"] = "";
-                       }
-               }
-
-               if(side["fog"].empty())
-                       side["fog"] = fog_game ? "yes" : "no";
-
-               if(side["shroud"].empty())
-                       side["shroud"] = shroud_game ? "yes" : "no";
-               
-               if(side["share_maps"].empty())
-                       side["share_maps"] = share_maps ? "yes" : "no";
-               
-               if(side["share_view"].empty())
-                       side["share_view"] = share_view ? "yes" : "no";
-
-               if(side["id"].empty())
-                       side["id"] = (*possible_sides.front())["id"];
-
-               if(side["name"].empty())
-                       side["name"] = (*possible_sides.front())["name"];
-
-               if(side["leader"].empty())
-                       side["leader"] = (*possible_sides.front())["leader"];
-
-               if(side["type"].empty() && save_ == false) {
-                       side["random_faction"] = 
(*possible_sides.front())["random_faction"];
-                       side["type"] = (*possible_sides.front())["type"];
-               }
-
-               if(side["recruit"].empty())
-                       side["recruit"] = (*possible_sides.front())["recruit"];
-
-               if(side["music"].empty())
-                       side["music"] = (*possible_sides.front())["music"];
+       combo_controller_.set_items(list);
+       update_controller_ui();
+}
 
-               if(side["terrain_liked"].empty())
-                       side["terrain_liked"] = 
(*possible_sides.front())["terrain_liked"];
+const std::string& connect::side::get_id() const 
+{
+       return id_;
+}
 
-               if(side["recruitment_pattern"].empty())
-                       side["recruitment_pattern"] = 
possible_sides.front()->values["recruitment_pattern"];
+void connect::side::set_id(const std::string& id) 
+{
+       connected_user_list::iterator i = parent_->find_player(id);
+       if (i != parent_->users_.end()) {
+               id_ = id;
+               controller_ = i->controller;
        }
+       update_ui();
+}
 
-       if((*level_)["objectives"] == "") {
-               (*level_)["objectives"] = _("Victory\n\
address@hidden enemy leader(s)");
-       }
+const std::string& connect::side::get_original_description() const 
+{
+       return original_description_;
+}
 
-       if(save_ == false) {
-               (*level_)["experience_modifier"] = 
lexical_cast<std::string>(xpmodifier);
-               (*level_)["era"] = era_;
-       }
+void connect::side::import_network_user(const config& data)
+{
+       id_ = data["name"];
+       controller_ = CNTR_NETWORK;
 
-       lists_init();
+       if (enabled_) {
+               faction_ = lexical_cast_default<int>(data["faction"], 0);
+               if (faction_ > int(parent_->era_sides_.size()))
+                       faction_ = 0;
+               llm_.update_leader_list(faction_);
+               llm_.set_leader(data["leader"]);
+       }
+       
+       update_ui();
+}
 
-       //if we have any connected players when we are created, send them the 
data
-       network::send_data(*level_);
+void connect::side::reset(mp::controller controller)
+{
+       id_ = "";
+       faction_ = 0;
+       controller_ = controller;
 
-       return 0;
+       llm_.update_leader_list(0);
+       update_ui();
 }
 
-void mp_connect::lists_init()
+void connect::side::resolve_random()
 {
-       //Options
-       player_types_.push_back(_("Network Player"));
-       player_types_.push_back(_("Local Player"));
-       player_types_.push_back(_("Computer Player"));
-       player_types_.push_back(_("Empty"));
-       player_types_.push_back("-----");
-       player_types_.push_back(preferences::login());
-
-       //Factions
-       const config::child_itors sides = level_->child_range("side");
+       if((*parent_->era_sides_[faction_])["random_faction"] == "yes") {
 
-       const config* const era_cfg = cfg_->find_child("era","id",era_);
-       if(era_cfg == NULL) {
-               return;
-       }
+               // Builds the list of sides which aren't random
+               std::vector<int> nonrandom_sides;
+               for(config::child_iterator itor = parent_->era_sides_.begin(); 
+                               itor != parent_->era_sides_.end(); ++itor) {
+                       if((**itor)["random_faction"] != "yes") {
+                               nonrandom_sides.push_back(itor - 
parent_->era_sides_.begin());
+                       }
+               }
 
-       const config::child_list& possible_sides = 
era_cfg->get_children("multiplayer_side");
+               if (nonrandom_sides.size() == 0) {
+                       throw config::error(_("No non-random sides in the 
current era"));
+               }
 
-       for(std::vector<config*>::const_iterator race = possible_sides.begin(); 
race != possible_sides.end(); ++race) {
-               player_races_.push_back((**race)["name"]);
-               possible_faction_ids_.push_back((**race)["id"]);
+               faction_ = nonrandom_sides[rand() % nonrandom_sides.size()];
        }
 
-       //Teams
-       config::child_iterator sd;
-       for(sd = sides.first; sd != sides.second; ++sd) {
-               const int side_num = (sd - sides.first) + 1;
-               (**sd)["colour"] = lexical_cast_default<std::string>(side_num);
-      
-               std::string& team_name = (**sd)["team_name"];
-               if (team_name.empty())
-                       team_name = lexical_cast<std::string>(side_num);
-      
-               const std::vector<std::string>::iterator result = 
-                       std::find(player_teams_.begin(), player_teams_.end(),
-                                 team_prefix_ + team_name);
-               
-               if (result == player_teams_.end()) {
-                       player_teams_.push_back(team_prefix_ + team_name);
-                       team_names_.push_back(team_name);
-                       team_indices_.push_back(player_teams_.size() - 1);
+       if (llm_.get_leader() == "random") {
+               // Choose a random leader type.  
+               const config& fact = *parent_->era_sides_[faction_];
+               std::vector<std::string> types = utils::split(fact["leader"]);
+               if (!types.empty()) {
+                       const int lchoice = rand() % types.size();
+                       leader_ = types[lchoice];
                } else {
-                       team_indices_.push_back(result - player_teams_.begin());
+                       throw config::error(_("Unable to find a leader type for 
faction ") + fact["name"]);
                }
-
-               player_leaders_.push_back(leader_list_manager(possible_sides, 
data_));
        }
-
-       std::string prefix;
-       prefix.resize(1);
-       //Colors
-       prefix[0] = 1;
-       player_colors_.push_back(prefix + _("Red"));
-       prefix[0] = 2;
-       player_colors_.push_back(prefix + _("Blue"));
-       prefix[0] = 3;
-       player_colors_.push_back(prefix + _("Green"));
-       prefix[0] = 4;
-       player_colors_.push_back(prefix + _("Yellow"));
-       prefix[0] = 5;
-       player_colors_.push_back(prefix + _("Purple"));
-       prefix[0] = 6;
-       player_colors_.push_back(prefix + _("Orange"));
-       prefix[0] = 7;
-       player_colors_.push_back(prefix + _("Grey"));
-       prefix[0] = 8;
-       player_colors_.push_back(prefix + _("White"));
-       prefix[0] = 9;
-       player_colors_.push_back(prefix + _("Brown"));
 }
 
-void mp_connect::add_player(const std::string& name)
-{
-       player_types_.push_back(name);
+connect::connect(display& disp, const config& game_config, const game_data& 
data,
+               chat& c, config& gamelist, const create::parameters& params, 
+               mp::controller default_controller) :
+       mp::ui(disp, game_config, c, gamelist),
 
-       for(size_t n = 0; n != combos_type_.size(); ++n) {
-               combos_type_[n].set_items(player_types_);
-       }
-}
+       game_data_(data),
 
-void mp_connect::remove_player(const std::string& name)
-{
-       const std::vector<std::string>::iterator itor = 
std::find(player_types_.begin(),player_types_.end(),name);
-       if(itor != player_types_.end())
-               player_types_.erase(itor);
+       waiting_label_(disp, _("")),
+       message_full_(false),
+       default_controller_(default_controller),
 
-       for(size_t n = 0; n != combos_type_.size(); ++n) {
-               combos_type_[n].set_items(player_types_);
-       }
-}
+       scroll_pane_(disp),
+       type_title_label_(disp, _("Player/Type"), font::SIZE_NORMAL, 
font::GOOD_COLOUR),
+       faction_title_label_(disp, _("Faction"), font::SIZE_NORMAL, 
font::GOOD_COLOUR),
+       team_title_label_(disp, _("Team"), font::SIZE_NORMAL, 
font::GOOD_COLOUR),
+       colour_title_label_(disp, _("Colour"), font::SIZE_NORMAL, 
font::GOOD_COLOUR),
+       gold_title_label_(disp, _("Gold"), font::SIZE_NORMAL, 
font::GOOD_COLOUR),
 
-void mp_connect::set_area(const SDL_Rect& rect)
+       ai_(disp, _("Computer vs Computer")),
+       launch_(disp, _("I'm Ready")),
+       cancel_(disp, _("Cancel"))
 {
-       rect_ = rect;
-
-       const int left = rect.x;
-       const int right = rect.x + rect.w;
-       const int top = rect.y;
-       const int bottom = rect.y + rect.h;
-
-       // Wait to players, Configure players
-       //gui::draw_dialog_background(left, right, width, height, *disp_, 
"menu");
+       // Send Initial information
+       config response;
+       config& create_game = response.add_child("create_game");
+       create_game["name"] = params.name;
+       network::send_data(response);
 
-       gui::button* left_button = &launch_;
-       gui::button* right_button = &cancel_;
+       load_game(params);
+       lists_init(!params.saved_game);
 
-#ifdef OK_BUTTON_ON_RIGHT
-       std::swap(left_button,right_button);
-#endif
+       // Adds the current user as default user.
+       users_.push_back(connected_user(preferences::login(), CNTR_LOCAL, 0));
+       update_user_combos();
+       wassert(sides_.size() > 0);
 
-       //Buttons
-       right_button->set_location(right - right_button->width() - 
gui::ButtonHPadding,bottom-right_button->height()-gui::ButtonVPadding);
-       left_button->set_location(right - right_button->width() - 
left_button->width() - 
gui::ButtonHPadding*2,bottom-left_button->height()-gui::ButtonVPadding);
-       
-       ai_.set_location(left+30, 
bottom-left_button->height()-gui::ButtonVPadding);
-       waiting_label_.set_location(ai_.location().x + ai_.location().w + 10, 
bottom-left_button->height()-gui::ButtonVPadding);
+       int side_choice = 0;
+       for(side_list::const_iterator s = sides_.begin(); s != sides_.end(); 
++s) {
+               if(s->get_original_description() == preferences::login()) {
+                       side_choice = s - sides_.begin();
+               }
+       }
+       sides_[side_choice].set_id(preferences::login());
 
-       //Title and labels
-       gui::draw_dialog_title(left,top,disp_,_("Game Lobby"));
+       update_playerlist_state();
 
-       SDL_Rect labelr = 
font::draw_text(NULL,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,
-                                                 _("Player/Type"),0,0);
-       font::draw_text(disp_,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,
-                       
_("Player/Type"),(left+30)+(launch_.width()/2)-(labelr.w/2),top+35);
-       labelr = 
font::draw_text(NULL,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,_("Faction"),0,0);
+       // Updates the "level_" variable, now that sides are loaded
+       update_level();
+       gamelist_updated();
 
-       font::draw_text(disp_,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,
-                       
_("Faction"),(left+145)+(launch_.width()/2)-(labelr.w/2),top+35);
-       
-       labelr = 
font::draw_text(NULL,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,_("Team"),0,0);
+       // If we are connected, send data to the connected host
+       network::send_data(level_);
+}
 
-       
font::draw_text(disp_,disp_->screen_area(),font::SIZE_NORMAL,font::GOOD_COLOUR,
-                       
_("Team"),(left+260)+(launch_.width()/2)-(labelr.w/2),top+35);
-       
-       labelr = 
font::draw_text(NULL,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,_("Color"),0,0);
+void connect::process_event()
+{
+       bool changed = false;
 
-       
font::draw_text(disp_,disp_->screen_area(),font::SIZE_NORMAL,font::GOOD_COLOUR,
-                       
_("Color"),(left+375)+(launch_.width()/2)-(labelr.w/2),top+35);
-       
-       labelr = 
font::draw_text(NULL,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,_("Gold"),0,0);
-       font::draw_text(disp_,rect,font::SIZE_NORMAL,font::GOOD_COLOUR,
-                       
_("Gold"),(left+480)+(launch_.width()/2)-(labelr.w/2),top+35);
+       for(size_t n = 0; n != sides_.size(); ++n) {
+               sides_[n].process_event();
+               if (sides_[n].changed())
+                       changed = true;
+       }
 
-       //Per player settings
-       const config::child_itors sides = level_->child_range("side");
+       if (cancel_.pressed()) {
+               if(network::nconnections() > 0) {
+                       config cfg;
+                       cfg.add_child("leave_game");
+                       network::send_data(cfg);
+               }
 
-       const config* const era_cfg = cfg_->find_child("era","id",era_);
-       if(era_cfg == NULL) {
+               set_result(QUIT);
                return;
        }
 
-       //Show buttons
-       ai_.hide(false);
-       launch_.hide(false);
-       cancel_.hide(false);
-       waiting_label_.hide(false);
-       scroll_pane_.hide(false);
-
-       SDL_Rect scroll_pane_rect;
-       scroll_pane_rect.x = rect.x;
-       scroll_pane_rect.y = rect.y + 50;
-       scroll_pane_rect.w = rect.w;
-       scroll_pane_rect.h = launch_.location().y - scroll_pane_rect.y - 
gui::ButtonVPadding;
-
-       scroll_pane_.set_location(scroll_pane_rect);
-       config::child_iterator sd;
-
-       for(sd = sides.first; sd != sides.second; ++sd) {
-               const int side_num = sd - sides.first;
-               LOG_CF << "Side num: " << side_num << std::endl;
+       if (ai_.pressed()) {
+               for(size_t m = 0; m != sides_.size(); ++m) {
+                       sides_[m].set_controller(CNTR_COMPUTER);
+               }
+               changed = true;
+       }
 
-               //Player number
-               player_numbers_.push_back(gui::label(*disp_, 
(*sd)->values["side"],
-                                       font::SIZE_XLARGE, font::GOOD_COLOUR));
-
-               //Player type
-               combos_type_.push_back(gui::combo(*disp_, player_types_));
-
-               //Player race
-               combos_race_.push_back(gui::combo(*disp_, player_races_));
-
-               //Player leader
-               std::vector<std::string> dummy_leaders;
-               dummy_leaders.push_back("-");
-               combos_leader_.push_back(gui::combo(*disp_, dummy_leaders));
-
-               //Player team
-               combos_team_.push_back(gui::combo(*disp_, player_teams_));
-               combos_team_.back().set_selected(team_indices_[ side_num ]);
-
-               //Player color
-               combos_color_.push_back(gui::combo(*disp_, player_colors_));
-               combos_color_.back().set_selected(side_num);
-
-               SDL_Rect r;
-
-               //Player gold
-               r.x = left+490;
-               r.y = top+55+(60*side_num);
-               r.w = launch_.width()-5;
-               r.h = launch_.height();
-
-               sliders_gold_.push_back(gui::slider(*disp_));
-               sliders_gold_.back().set_min(20);
-               sliders_gold_.back().set_max(1000);
-               sliders_gold_.back().set_increment(25);
-               
sliders_gold_.back().set_value(lexical_cast_default<int>((**sd)["gold"],100));
-               sliders_gold_.back().set_location(r);
-
-               labels_gold_.push_back(gui::label(*disp_, "100", 
font::SIZE_NORMAL, font::GOOD_COLOUR));
-
-               combos_race_.back().enable(!save_);
-               combos_leader_.back().enable(!save_);
-               combos_team_.back().enable(!save_);
-               combos_color_.back().enable(!save_);
+       if (launch_.pressed()) {
+               if (!sides_available())
+                       set_result(mp::ui::PLAY);
        }
 
-               
-       //Doing this after creating the combos, because growing vectors may
-       //move their elements in memory, and we need a stable pointer
-       for(sd = sides.first; sd != sides.second; ++sd) {
-               const int side_num = sd - sides.first;
-               const int spos = 60 * side_num;
+       // If something has changed in the level config, send it to the
+       // network:
+       if (changed) {
+               update_playerlist_state();
 
-               scroll_pane_.add_widget(&player_numbers_[side_num], 10, 3 + 
spos);
-               scroll_pane_.add_widget(&combos_type_[side_num], 30, 5 + spos);
-               scroll_pane_.add_widget(&combos_race_[side_num], 145, 5 + spos);
-               scroll_pane_.add_widget(&combos_leader_[side_num], 145, 35 + 
spos);
-               scroll_pane_.add_widget(&combos_team_[side_num], 260, 5 + spos);
-               scroll_pane_.add_widget(&combos_color_[side_num], 375, 5 + 
spos);
-               scroll_pane_.add_widget(&sliders_gold_[side_num], 490, 5 + 
spos);
-               scroll_pane_.add_widget(&labels_gold_[side_num], 500 + 
sliders_gold_[side_num].width(), 5 + spos);
+               config old_level = level_;
+               update_level();
+               
+               config diff;
+               diff.add_child("scenario_diff",level_.get_diff(old_level));
 
-               player_leaders_[side_num].set_combo(&combos_leader_[side_num]);
+               network::send_data(diff);
        }
-
-       LOG_CF << "done set_area()\n";
-
-       update_whole_screen();
 }
 
-void mp_connect::clear_area()
+const config& connect::get_level()
 {
-       scroll_pane_.clear();
-
-       combos_type_.clear();
-       combos_race_.clear();
-       combos_leader_.clear();
-       combos_team_.clear();
-       combos_color_.clear();
-       sliders_gold_.clear();
-       labels_gold_.clear();
-       possible_faction_ids_.clear();
+       return level_;
+}
 
-       ai_.hide();
-       launch_.hide();
-       cancel_.hide();
-       waiting_label_.hide();
-       scroll_pane_.hide();
+const game_state& connect::get_state()
+{
+       return state_;
 }
 
-void mp_connect::gui_update()
+void connect::start_game()
 {
-       //Update the GUI based on current config settings.
-       //Settings may change based on other networked
-       //players.
+       // Resolves the "random faction" and "random message"
+       for (side_list::iterator itor = sides_.begin(); itor != sides_.end(); 
+                       ++itor) {
 
-       const config* const era_cfg = cfg_->find_child("era","id",era_);
-       if(era_cfg == NULL) {
-               return;
+               itor->resolve_random();
        }
 
-       const config::child_itors sides = level_->child_range("side");
+       update_level();
 
-       for(size_t n = 0; n != combos_type_.size(); ++n) {
-               config& side = **(sides.first+n);
+       // FIXME: This is to be reviewed!
+       recorder.set_save_info(state_);
+       recorder.set_skip(-1);
+       level_.clear_children("replay");
+       state_.snapshot = level_;
+       state_.players.clear();
 
-               //Player type
-               if (side["controller"] == "network") {
-                       if (side["description"] == "") {
-                               combos_type_[n].set_selected(0);
-                       } else if (side["description"] == _("Computer Player")) 
{
-                               //When loading a game you did not create AI 
players are marked
-                               //as network players, set back to AI
-                               combos_type_[n].set_selected(2);
-                       } else {
-                               for (size_t m = 0; m != player_types_.size(); 
++m) {
-                                       if (side["description"] == 
player_types_[m]) {
-                                               combos_type_[n].set_selected(m);
-                                       }
-                               }
-                       }
-               } else if (side["controller"] == "human") {
-                       if (side["description"] == preferences::login()) {
-                               combos_type_[n].set_selected(5);
-                       } else if (side["description"] != "") {
-                               //When loading a game and you use a name not 
originally used during
-                               //the initial game, mark that original slot as 
network
-                               combos_type_[n].set_selected(0);
-                       } else {
-                               combos_type_[n].set_selected(1);
-                       }
-               } else if (side["controller"] == "ai") {
-                       combos_type_[n].set_selected(2);
-               } else if(side["controller"] == "null") {
-                       combos_type_[n].set_selected(3);
-               }
+       config lock;
+       lock.add_child("stop_updates");
+       network::send_data(lock);
 
-               //Player Faction
-               for (size_t m = 0; m != player_races_.size(); ++m) {
-                       if (side["id"] == possible_faction_ids_[m]) {
-                               if (combos_race_[n].selected() != m) {
-                                       combos_race_[n].set_selected(m);
+       // Re-sends the whole level
+       network::send_data(level_);
 
-                                       if (!save_)
-                                               
player_leaders_[n].update_leader_list(m);
-                               }
-                       }
-               }
-
-               // Player leader
-               if (!save_) 
-                       player_leaders_[n].set_leader(side["type"]);
-
-               //Player Gold
-               labels_gold_[n].set_text(side["gold"]);
-       }
+       config cfg;
+       cfg.add_child("start_game");
+       network::send_data(cfg);
 
-       const bool full = is_full();
-       if(full != message_full_) {
-               message_full_ = full;
-               if(full) {
-                       waiting_label_.set_text("");
-               } else {
-                       waiting_label_.set_text(_("Waiting for network players 
to join"));
-               }
-       }
 }
 
-lobby::RESULT mp_connect::process()
+void connect::hide_children(bool hide)
 {
-       if(old_level_.empty()) {
-               old_level_ = *level_;
-       }
+       mp::ui::hide_children(hide);
 
-       const config* const era_cfg = cfg_->find_child("era","id",era_);
+       waiting_label_.hide(hide);
+       // Hiding the scrollpane automatically hides its contents
+       scroll_pane_.hide(hide);
+       type_title_label_.hide(hide);
+       faction_title_label_.hide(hide);
+       team_title_label_.hide(hide);
+       colour_title_label_.hide(hide);
+       gold_title_label_.hide(hide);
 
-       if(era_cfg == NULL) {
-               ERR_CF << "cannot find era '" << era_ << "'\n";
-               return lobby::QUIT;
-       }
+       ai_.hide(hide);
+       launch_.hide(hide);
+       cancel_.hide(hide);
+}
 
-       const config::child_list& possible_sides = 
era_cfg->get_children("multiplayer_side");
+void connect::gamelist_updated()
+{
+       update_playerlist_state();
+}
 
-       const config::child_itors sides = level_->child_range("side");
+void connect::process_network_data(const config& data, const 
network::connection sock)
+{
+       mp::ui::process_network_data(data, sock);
 
-       bool start_game = false;
-
-       bool level_changed = false;
-
-       for(size_t n = 0; n != combos_team_.size(); ++n) {
-               config& side = **(sides.first+n);
-
-               //Player type
-               //Don't let user change this if a player is sitting
-               combos_type_[n].enable(combos_type_[n].selected() < 4);
-
-               if (combos_type_[n].changed()) {
-                       switch (combos_type_[n].selected()) {
-                       case 1:
-                               side["controller"] = "human";
-                               side["description"] = "";
-                               break;
-                       case 2:
-                               side["controller"] = "ai";
-                               side["description"] = _("Computer Player");
-                               break;
-                       case 3:
-                               side["controller"] = "null";
-                               side["description"] = "";
-                               break;
-                       case 5: {
-                               side["controller"] = "human";
-                               side["description"] = preferences::login();
-                               for(size_t m = 0; m != combos_type_.size(); 
++m) {
-                                       if(m != n) {
-                                               if(combos_type_[m].selected() 
== 5){
-                                                       
combos_type_[m].set_selected(2);
-                                                       config& si = 
**(sides.first+m);
-                                                       si["controller"] = "ai";
-                                                       si["description"] = "";
-                                               }
-                                       }
-                               }
-                               break;
-                       }
-                       case 4:
-                               combos_type_[n].set_selected(0);
-                       case 0:
-                               side["controller"] = "network";
-                               side["description"] = "";
-                               break;
-                       default:
-                               // Do nothing
-                               ;
+       if (!data["side_drop"].empty()) {
+               const int side_drop = 
lexical_cast_default<int>(data["side_drop"], 0) - 1;
+               if(side_drop >= 0 && side_drop < int(sides_.size())) {
+                       connected_user_list::iterator player = 
find_player(sides_[side_drop].get_id());
+                       sides_[side_drop].reset(default_controller_);
+                       if (player != users_.end()) {
+                               users_.erase(player);
+                               update_user_combos();
                        }
 
-                       level_changed = true;
+                       network::send_data(level_);
+                       return;
                }
+       }
 
-               if (!save_ && combos_race_[n].changed()) {
-                       const string_map& values =  
possible_sides[combos_race_[n].selected()]->values;
-                       side["random_faction"] = "";
-                       for(string_map::const_iterator i = values.begin(); i != 
values.end(); ++i) {
-                               LOG_CF << "value: " << i->first << " , " << 
i->second << std::endl;
-                               side[i->first] = i->second;
-                       }
-                       level_changed = true;
+       if (!data["side"].empty()) {
+               int side_taken = lexical_cast_default<int>(data["side"], 0);
 
-                       
player_leaders_[n].update_leader_list(combos_race_[n].selected());
-               }
-               
-               //Player colour
-               if (combos_color_[n].changed()) {
-                       side["colour"] = 
lexical_cast_default<std::string>(combos_color_[n].selected()+1);
-                       level_changed = true;
-               }
-
-               //Player leader
-               if (!save_ && combos_leader_[n].changed()) {
-                       side["type"] = player_leaders_[n].get_leader();
-                       level_changed = true;
+               // Checks if the connecting user has a valid and unique name.
+               const std::string name = data["name"];
+               if (name.empty() || find_player(name) != users_.end()) {
+                       config response;
+                       response.values["failed"] = "yes";
+                       network::send_data(response,sock);
+                       return;
                }
 
-               //Player team
-               if (combos_team_[n].changed()) {
-                       side["team_name"] = 
team_names_[combos_team_[n].selected()];
-                       level_changed = true;
-               }
 
-               if(!save_){
-                       const int cur_playergold = sliders_gold_[n].value();
-                       std::stringstream playergold;
-                       playergold << cur_playergold;
-                       if (side["gold"] != playergold.str())
-                       {
-                               side["gold"] = playergold.str();
-
-                               //Player Gold
-                               labels_gold_[n].set_text(side["gold"]);
-                               level_changed = true;
+               // Assigns this user to a side
+               if(side_taken >= 0 && side_taken < int(sides_.size())) {
+                       if(!sides_[side_taken].available()) {
+                               // This side is already taken. Try to reassing 
the player to a
+                               // different position
+                               side_list::const_iterator itor;
+                               side_taken = 0;
+                               for (itor = sides_.begin(); itor != 
sides_.end();
+                                               ++itor, ++side_taken) {
+                                       if(itor->available())
+                                               break;
+                               }
+
+                               if(itor == sides_.end()) {
+                                       config response;
+                                       response.values["failed"] = "yes";
+                                       network::send_data(response, sock);
+                                       return;
+                               }
                        }
-               }
-       }
 
-       if (cancel_.pressed()) {
-               if(network::nconnections() > 0) {
-                       config cfg;
-                       cfg.add_child("leave_game");
-                       network::send_data(cfg);
-               }
+                       LOG_CF << "client has taken a valid position\n";
+
+                       // Adds the name to the list
+                       users_.push_back(connected_user(name, CNTR_NETWORK, 
sock));
+                       update_user_combos();
+
+                       // sides_[side_taken].set_connection(sock);
+                       sides_[side_taken].import_network_user(data);
+                       update_level();
+                       update_playerlist_state();
+                       network::send_data(level_);
 
-               return lobby::QUIT;
-       }
+                       LOG_NW << "sent player data\n";
 
-       if (ai_.pressed()) {
-               for(size_t m = 0; m != combos_team_.size(); ++m) {
-                       config& si = **(sides.first+m);
-                       //disconnect everyone except the host
-                       std::map<config*,network::connection>::iterator pos = 
positions_.find(&si);
-                       if (pos->first->values["description"] == 
si["description"]) {
-                               network::disconnect(pos->second);
-                               pos->second = 0;
-                       }
-                       pos->first->values.erase("taken");
-                       remove_player(pos->first->values["description"]);
-                       if(!save_) {
-                               si["description"] = _("Computer Player");
-                               si["controller"] = "ai";
-                               si["id"] = possible_faction_ids_.front();
-                               si["random_faction"] = "yes";
-                       }
+               } else {
+                       ERR_CF << "tried to take illegal side: " << side_taken 
<< '\n';
+                       config response;
+                       response.values["failed"] = "yes";
+                       network::send_data(response, sock);
                }
-               level_changed = true;
        }
+}
 
-       launch_.enable(is_full());
-
-       if (launch_.pressed()) {
-               const config::child_list& real_sides = 
era_cfg->get_children("multiplayer_side");
-
-               for(config::child_iterator side = sides.first; side != 
sides.second; ++side) {
-                       int ntry = 0;
-                       while((**side)["random_faction"] == "yes" && ntry < 
1000) {
-                               const int choice = rand()%real_sides.size();
-
-                               (**side)["id"] = (*real_sides[choice])["id"];
-                               (**side)["name"] = 
(*real_sides[choice])["name"];
-                               (**side)["random_faction"] = 
(*real_sides[choice])["random_faction"];
-
-                               (**side)["type"] = "random";
+void connect::process_network_error(network::error& error)
+{
+       //if the problem isn't related to any specific connection,
+       //it's a general error and we should just re-throw the error
+       //likewise if we are not a server, we cannot afford any connection
+       //to go down, so also re-throw the error
+       if(!error.socket || !network::is_server()) {
+               error.disconnect();
+               throw network::error(error.message);
+       }
 
-                               (**side)["leader"] = 
(*real_sides[choice])["leader"];
-                               (**side)["recruit"] = 
(*real_sides[choice])["recruit"];
-                               (**side)["music"] = 
(*real_sides[choice])["music"];
+       bool changes = false;
 
-                               (**side)["recruitment_pattern"] = 
real_sides[choice]->values["recruitment_pattern"];
-                               (**side)["terrain_liked"] = 
(*real_sides[choice])["terrain_liked"];
-                               level_changed = true;
+       //a socket has disconnected. Remove it, and resets its side
+       connected_user_list::iterator user;
+       for(user = users_.begin(); user != users_.end(); ++user) {
+               if(user->connection == error.socket) {
+                       changes = true;
 
-                               ++ntry;
-                       }
+                       int i = find_player_side(user->name);
+                       if (i != -1)
+                               sides_[i].reset(default_controller_);
 
-                       if ((**side)["type"] == "random" || 
(**side)["type"].empty()) {
-                               // Choose a random leader type.  
-                               std::vector<std::string> types = 
-                                       utils::split((**side)["leader"]);
-                               if (!types.empty()) {
-                                       const int lchoice = rand() % 
types.size();
-                                       (**side)["type"] = types[lchoice];
-                               } else {
-                                       ERR_CF << "Unable to find a type for 
side " << (**side)["name"] << "!\n";
-                               }
-                               level_changed = true;
-                       }
+                       break;
                }
-
-               start_game = true;
        }
-
-       if(level_changed) {
-               config diff;
-               diff.add_child("scenario_diff",level_->get_diff(old_level_));
-
-               network::send_data(diff);
-
-               old_level_ = *level_;
+       if(user != users_.end()) {
+               users_.erase(user);
+               update_user_combos();
        }
 
-       if(start_game) {
-               LOG_G << "multiplayer_connect returning create...\n";
-               return lobby::CREATE;
-       }
-
-       update_positions();
-       update_network();
-       gui_update();
+       //now disconnect the socket
+       error.disconnect();
 
-       return lobby::CONTINUE;
+       //if there have been changes to the positions taken,
+       //then notify other players
+       if(changes) {
+               // FIXME: shouldn't a diff be sent here instead?
+               update_level();
+               network::send_data(level_);
+               update_playerlist_state();
+       }
 }
 
-bool mp_connect::get_network_data(config& cfg)
+bool connect::accept_connections()
 {
-       if(network_data_.empty() == false) {
-               cfg = network_data_.front();
-               network_data_.pop_front();
+       if (sides_available())
                return true;
-       } else {
-               return false;
-       }
+       return false;
 }
 
-void mp_connect::start_game()
+void connect::process_network_connection(const network::connection sock)
 {
-       clear_area();
+       ui::process_network_connection(sock);
 
-       //Tell everyone to start
        config cfg;
-       cfg.add_child("start_game");
+       cfg.add_child("join_game");
        network::send_data(cfg);
 
-       recorder.set_save_info(*state_);
+       network::send_data(level_, sock);
+}
 
-       //see if we should show the replay of the game so far
-       if(!recorder.empty()) {
-               if(false) {
-                       recorder.set_skip(0);
-               } else {
-                       LOG_G << "skipping...\n";
-                       recorder.set_skip(-1);
-               }
-       }
+void connect::layout_children(const SDL_Rect& rect)
+{
+       mp::ui::layout_children(rect);
 
-       state_->snapshot = *level_;
+       SDL_Rect ca = client_area();
 
-       if(save_ == false) {
-               state_->starting_pos = *level_;
-       }
+       gui::button* left_button = &launch_;
+       gui::button* right_button = &cancel_;
+#ifdef OK_BUTTON_ON_RIGHT
+       std::swap(left_button,right_button);
+#endif
+       size_t left = ca.x;
+       size_t right = ca.x + ca.w;
+       size_t top = ca.y;
+       size_t bottom = ca.y + ca.h;
 
-       //any replay data isn't meant to hang around under the level,
-       //it was just there to tell clients about the replay data
-       level_->clear_children("replay");
-       std::vector<config*> story;
-       state_->players.clear();
+       //Buttons
+       right_button->set_location(right - right_button->width() - 
gui::ButtonHPadding,
+                       bottom - right_button->height() - gui::ButtonVPadding);
+       left_button->set_location(right - right_button->width() - 
left_button->width() - gui::ButtonHPadding*2,
+                       bottom - left_button->height()-gui::ButtonVPadding);
 
-       play_level(*data_, *cfg_, level_, disp_->video(), *state_, story);
-       recorder.clear();
+       ai_.set_location(left+30, 
bottom-left_button->height()-gui::ButtonVPadding);
+       waiting_label_.set_location(ai_.location().x + ai_.location().w + 10,
+                       bottom-left_button->height()-gui::ButtonVPadding);
 
-       if(network::nconnections() > 0) {
-               config cfg;
-               cfg.add_child("leave_game");
-               network::send_data(cfg);
-       }
-}
+       // Title and labels
+       gui::draw_dialog_title(left,top,&disp(),_("Game Lobby"));
 
-void mp_connect::update_positions()
-{
-       const config::child_itors sides = level_->child_range("side");
+       
type_title_label_.set_location((left+30)+(launch_.width()/2)-(type_title_label_.width()/2),top+35);
+       
faction_title_label_.set_location((left+145)+(launch_.width()/2)-(faction_title_label_.width()/2),top+35);
+       
team_title_label_.set_location((left+260)+(launch_.width()/2)-(team_title_label_.width()/2),top+35);
+       
colour_title_label_.set_location((left+375)+(launch_.width()/2)-(colour_title_label_.width()/2),top+35);
+       
gold_title_label_.set_location((left+480)+(launch_.width()/2)-(gold_title_label_.width()/2),top+35);
+
+       SDL_Rect scroll_pane_rect;
+       scroll_pane_rect.x = ca.x;
+       scroll_pane_rect.y = ca.y + 50;
+       scroll_pane_rect.w = ca.w;
+       scroll_pane_rect.h = launch_.location().y - scroll_pane_rect.y - 
gui::ButtonVPadding;
+
+       scroll_pane_.set_location(scroll_pane_rect);
        config::child_iterator sd;
-       for(sd = sides.first; sd != sides.second; ++sd) {
-               if((**sd)["taken"] != "yes") {
-                       positions_[*sd] = 0;
-               }
-       }
 }
 
-void mp_connect::update_network()
+void connect::lists_init(bool changes_allowed)
 {
-       for(std::map<config*,network::connection>::const_iterator i = 
positions_.begin(); i != positions_.end(); ++i) {
-               if(!i->second) {
-                       //We are waiting on someone
-                       network::connection sock = network::accept_connection();
-                       if(sock) {
-                               LOG_NW << "Received connection\n";
-                               network::send_data(*level_,sock);
-                       }
-               }
+       //Options
+       player_types_.push_back(_("Network Player"));
+       player_types_.push_back(_("Local Player"));
+       player_types_.push_back(_("Computer Player"));
+       player_types_.push_back(_("Empty"));
+
+       const config* const era_cfg = game_config().find_child("era","id",era_);
+       if(era_cfg == NULL) {
+               throw config::error(_("Era not available") + std::string(": ") 
+ era_);
        }
 
-       config cfg;
-       const config::child_list& sides = level_->get_children("side");
+       era_sides_ = era_cfg->get_children("multiplayer_side");
 
-       network::connection sock;
+       for(std::vector<config*>::const_iterator faction = era_sides_.begin(); 
faction != era_sides_.end(); ++faction) {
+               player_factions_.push_back((**faction)["name"]);
+       }
 
-       try {
-               sock = network::receive_data(cfg);
-       } catch(network::error& e) {
-               ERR_NW << "caught networking error. we are " << 
(network::is_server() ? "" : "NOT") << " a server\n";
-               sock = 0;
-
-               //if the problem isn't related to any specific connection,
-               //it's a general error and we should just re-throw the error
-               //likewise if we are not a server, we cannot afford any 
connection
-               //to go down, so also re-throw the error
-               if(!e.socket || !network::is_server()) {
-                       e.disconnect();
-                       throw network::error(e.message);
-               }
 
-               bool changes = false;
+       //Factions
+       const config::child_itors sides = level_.child_range("side");
 
-               //a socket has disconnected. Remove its positions.
-               for(std::map<config*,network::connection>::iterator i = 
positions_.begin(); i != positions_.end(); ++i) {
-                       if(i->second == e.socket) {
-                               changes = true;
-                               i->second = 0;
-                               i->first->values.erase("taken");
-                               remove_player(i->first->values["description"]);
-                               if(!save_) {
-                                       i->first->values["description"] = "";
-                                       i->first->values["id"] = 
possible_faction_ids_.front();
-                                       i->first->values["random_faction"] = 
"yes";
-                                       i->first->values["type"] = "";
-                               }
-                       }
+       //Teams
+       config::child_iterator sd;
+       for(sd = sides.first; sd != sides.second; ++sd) {
+               const int team_num = sd - sides.first;
+               std::string& team_name = (**sd)["team_name"];
+               if(team_name.empty()) {
+                       team_name = lexical_cast<std::string>(team_num+1);
                }
 
-               //now disconnect the socket
-               e.disconnect();
+               player_teams_.push_back(_("Team") + std::string(" ") + 
team_name);
+               (**sd)["colour"] = 
lexical_cast_default<std::string>(team_num+1);
+       }
 
-               //if there have been changes to the positions taken,
-               //then notify other players
-               if(changes) {
-                       network::send_data(*level_);
-               }
+       std::string prefix;
+       prefix.resize(1);
+       //Colors
+       prefix[0] = 1;
+       player_colours_.push_back(prefix + _("Red"));
+       prefix[0] = 2;
+       player_colours_.push_back(prefix + _("Blue"));
+       prefix[0] = 3;
+       player_colours_.push_back(prefix + _("Green"));
+       prefix[0] = 4;
+       player_colours_.push_back(prefix + _("Yellow"));
+       prefix[0] = 5;
+       player_colours_.push_back(prefix + _("Purple"));
+       prefix[0] = 6;
+       player_colours_.push_back(prefix + _("Orange"));
+       prefix[0] = 7;
+       player_colours_.push_back(prefix + _("Grey"));
+       prefix[0] = 8;
+       player_colours_.push_back(prefix + _("White"));
+       prefix[0] = 9;
+       player_colours_.push_back(prefix + _("Brown"));
+
+       // Populates "sides_" from the level configuration
+       sides_.reserve(sides.second - sides.first);
+       int index = 0;
+       for(sd = sides.first; sd != sides.second; ++sd, ++index) {
+               sides_.push_back(side(*this, **sd, index, 100, 
changes_allowed));
+       }
+       // This function must be called after the sides_ vector is fully 
populated.
+       for(side_list::iterator sd = sides_.begin(); sd != sides_.end(); ++sd) {
+               const int side_num = sd - sides_.begin();
+               const int spos = 60 * side_num;
+
+               sd->add_widgets_to_scrollpane(scroll_pane_, spos);
        }
+}
 
-       //No network errors
-       if(sock) {
-               //check if this is a message that might be useful to our caller
-               if(cfg.child("message") || cfg.child("gamelist")) {
-                       network_data_.push_back(cfg);
+// Called by the constructor to initialize the game from a create::parameters 
structure.
+void connect::load_game(const create::parameters& params)
+{
+       if(params.saved_game) {
+               bool show_replay = false;
+               const std::string game = dialogs::load_game_dialog(disp(), 
game_config(), game_data_, &show_replay);
+               if(game.empty()) {
+                       set_result(QUIT);
                        return;
                }
+               
+               //state_.players.clear();
+               ::load_game(game_data_, game, state_);
 
-               const int side_drop = atoi(cfg["side_drop"].c_str())-1;
-               if(side_drop >= 0 && side_drop < int(sides.size())) {
-                       std::map<config*,network::connection>::iterator pos = 
positions_.find(sides[side_drop]);
-                       if(pos != positions_.end()) {
-                               pos->second = 0;
-                               pos->first->values.erase("taken");
-                               
remove_player(pos->first->values["description"]);
-                               if(!save_) {
-                                       pos->first->values["description"] = "";
-                                       pos->first->values["id"] = 
possible_faction_ids_.front();
-                                       pos->first->values["random_faction"] = 
"yes";
-                                       pos->first->values["type"] = "";
-                               }
-                               network::send_data(*level_);
-                       }
+               if(state_.campaign_type != "multiplayer") {
+                       gui::show_dialog(disp(), NULL, "", _("This is not a 
multiplayer save"),
+                                       gui::OK_ONLY);
+                       set_result(QUIT);
                        return;
                }
 
-               int side_taken = atoi(cfg["side"].c_str())-1;
-               if(side_taken >= 0 && side_taken < int(sides.size())) {
-                       std::map<config*,network::connection>::iterator pos = 
positions_.find(sides[side_taken]);
-                       if(pos != positions_.end()) {
-                               //see if we can reassign the player to a 
different position
-                               if(pos->second && pos->second != sock) {
-                                       side_taken = 0;
-                                       for(pos = positions_.begin(); pos != 
positions_.end(); ++pos, ++side_taken) {
-                                               
if(pos->first->values["controller"] == "network" &&
-                                                       
pos->first->values["taken"] != "yes") {
-                                                       break;
-                                               }
-                                       }
-
-                                       if(pos == positions_.end()) {
-                                               config response;
-                                               response.values["failed"] = 
"yes";
-                                               
network::send_data(response,sock);
-                                               return;
-                                       }
+               if(state_.version != game_config::version) {
+                       const int res = gui::show_dialog(disp(), NULL, "",
+                                       _("This save is from a different 
version of the game. Do you want to try to load it?"),
+                                       gui::YES_NO);
+                       if(res == 1) {
+                               set_result(QUIT);
+                               return;
+                       }
+               }
 
-                                       config reassign;
-                                       config& cfg = 
reassign.add_child("reassign_side");
-                                       cfg["from"] = cfg["side"];
-                                       cfg["to"] = 
lexical_cast<std::string>(side_taken+1);
-                                       network::send_data(reassign,sock);
-                               }
+               level_ = state_.snapshot;
 
-                               LOG_CF << "client has taken a valid position\n";
+               recorder = replay(state_.replay_data);
 
-                               //broadcast to everyone the new game status
-                               pos->first->values["controller"] = "network";
-                               pos->first->values["taken"] = "yes";
+               //if this is a snapshot save, we don't want to use the replay 
data
+               if(level_["snapshot"] == "yes") {
+                       config* const start = level_.child("start");
+                       if(start != NULL)
+                               start->clear_children("replay");
+                       level_.clear_children("replay");
+                       recorder.set_to_end();
+               } else {
+                       //add the replay data under the level data so clients 
can
+                       //receive it
+                       level_.clear_children("replay");
+                       level_.add_child("replay") = state_.replay_data;
+               }
 
-                               if(cfg["description"].empty() == false) {
-                                       pos->first->values["description"] = 
cfg["description"];
-                               }
+               // Gets the era from the era of the savegame
+               era_ = level_["era"];
+               if(era_.empty())
+                       era_ = params.era;
 
-                               if(cfg["id"].empty() == false) {
-                                       const config* const era_cfg = 
cfg_->find_child("era","id",era_);
-                                       const config::child_list& 
possible_sides = era_cfg->get_children("multiplayer_side");
-                                       const 
std::vector<std::string>::const_iterator itor = 
-                                               
std::find(possible_faction_ids_.begin(), possible_faction_ids_.end(), cfg["id"] 
);
-                                       if(itor == possible_faction_ids_.end()) 
{
-                                               ERR_CF << "client sent unknown 
faction id: " << cfg["id"] << "\n";
-                                       } else {
-                                               const int index = itor - 
possible_faction_ids_.begin();
-                                               const string_map& values = 
possible_sides[index]->values;
-                                               
pos->first->values["random_faction"] = "";
-                                               for(string_map::const_iterator 
i = values.begin(); i != values.end(); ++i) {
-                                                       LOG_CF << "value: " << 
i->first << " , " << i->second << std::endl;
-                                                       
pos->first->values[i->first] = i->second;
-                                               }
-                                               pos->first->values["id"] = 
cfg["id"];
-                                       }
-                               }
+       } else {
+               level_ = params.scenario_data;
+               level_["turns"] = 
lexical_cast_default<std::string>(params.num_turns, "20");
 
-                               if(cfg["name"].empty() == false) {
-                                       pos->first->values["name"] = 
cfg["name"];
-                               }
+               era_ = params.era;
+               level_["era"] = era_;
+       }
+       
+       // Initialize the list of sides available for the current era.
+       const config* const era_cfg = game_config().find_child("era","id",era_);
+       if(era_cfg == NULL) {
+               throw config::error(_("Cannot find era ") + era_);
+       }
+       era_sides_ = era_cfg->get_children("multiplayer_side");
 
-                               if(cfg["type"].empty() == false) {
-                                       pos->first->values["random_faction"] = 
"";
-                                       pos->first->values["type"] = 
cfg["type"];
-                               }
+       //this will force connecting clients to be using the same version 
number as us.
+       level_["version"] = game_config::version;
 
-                               if(cfg["recruit"].empty() == false) {
-                                       pos->first->values["recruit"] = 
cfg["recruit"];
-                               }
+       state_.label = level_["name"];
+       state_.players.clear();
+       state_.scenario = params.name;
+       state_.campaign_type = "multiplayer";
 
-                               if(cfg["music"].empty() == false) {
-                                       pos->first->values["music"] = 
cfg["music"];
-                               }
+       level_["observers"] = params.allow_observers ? "yes" : "no";
 
-                               if(cfg["random_faction"].empty() == false) {
-                                       pos->first->values["random_faction"] = 
cfg["random_faction"];
-                               }
+       if(level_["objectives"].empty()) {
+               level_["objectives"] = _("Victory\n\
address@hidden enemy leader(s)");
+       }
+}
 
-                               if(cfg["terrain_liked"].empty() == false) {
-                                       pos->first->values["terrain_liked"] = 
cfg["terrain_liked"];
-                               }
+void connect::update_level()
+{
+       // Import all sides into the level
+       level_.clear_children("side");
+       for(side_list::const_iterator itor = sides_.begin(); itor != 
sides_.end(); 
+                       ++itor) {
 
-                               pos->second = sock;
-                               network::send_data(*level_);
+               level_.add_child("side", itor->get_config());
+       }
+}
 
-                               LOG_NW << "sent player data\n";
+bool connect::sides_available()
+{
+       for(side_list::const_iterator itor = sides_.begin(); itor != 
sides_.end(); ++itor) {
+               if (itor->available())
+                       return true;
+       }
+       return false;
+}
 
-                               //send a reply telling the client they have 
secured
-                               //the side they asked for
-                               std::stringstream side;
-                               side << (side_taken+1);
-                               config reply;
-                               reply.values["side_secured"] = side.str();
-                               LOG_NW << "going to send data...\n";
-                               network::send_data(reply,sock);
+void connect::update_playerlist_state()
+{
+       waiting_label_.set_text(sides_available() ? _("Waiting for players to 
join...") : "");
+       launch_.enable(!sides_available());
 
-                               // Add to combo list
-                               add_player(cfg["description"]);
-                       } else {
-                               ERR_CF << "tried to take illegal side: " << 
side_taken << '\n';
-                       }
+       // If the "gamelist_" variable has users, use it. Else, extracts the
+       // user list from the actual player list.
+       if (gamelist().child("user") != NULL) {
+               ui::gamelist_updated();
+       } else {
+               // Updates the player list
+               std::vector<std::string> playerlist;
+               for(connected_user_list::const_iterator itor = users_.begin(); 
itor != users_.end();
+                               ++itor) {
+                       playerlist.push_back(itor->name);
                }
+               set_user_list(playerlist);
        }
 }
 
-bool mp_connect::is_full()
+connect::connected_user_list::iterator connect::find_player(const std::string& 
id)
 {
-       //see if all positions are now filled
-       bool full = true;
-       const config::const_child_itors sides = level_->child_range("side");
-
-       for(config::const_child_iterator sd = sides.first; sd != sides.second; 
++sd) {
-               if((**sd)["controller"] == "network" && positions_[*sd] == 0) {
-                       full = false;
-               }
+       connected_user_list::iterator itor;
+       for (itor = users_.begin(); itor != users_.end(); ++itor) {
+               if (itor->name == id)
+                       break;
+       }
+       return itor;
+}
+
+int connect::find_player_side(const std::string& id) const
+{
+       side_list::const_iterator itor;
+       for (itor = sides_.begin(); itor != sides_.end(); ++itor) {
+               if (itor->get_id() == id)
+                       break;
        }
 
-       return full;
+       if (itor == sides_.end())
+               return -1;
+
+       return itor - sides_.begin();
 }
+
+void connect::update_user_combos()
+{
+       for (side_list::iterator itor = sides_.begin(); itor != sides_.end(); 
++itor) {
+               itor->update_user_list();
+       }
+}
+
+void connect::kick_player(const std::string& name)
+{
+       connected_user_list::iterator player = find_player(name);
+       if(player == users_.end())
+               return;
+
+       if(player->controller != CNTR_NETWORK)
+               return;
+
+       // If we are the server, kick the user ourselves; else, ask the server
+       // to do so.
+       if(network::is_server()) {
+               network::disconnect(player->connection);
+       } else {
+               config kick;
+               kick["username"] = name;
+               config res;
+               res.add_child("kick", kick);
+               network::send_data(res);
+       }
+
+       int side = find_player_side(name);
+       if (side != -1) {
+               wassert(size_t(side) < sides_.size());
+               sides_[side].reset(sides_[side].get_controller());
+       }
+       users_.erase(player);
+       update_user_combos();
+}
+
+}
+
+
Index: wesnoth/src/multiplayer_connect.hpp
diff -u wesnoth/src/multiplayer_connect.hpp:1.24 
wesnoth/src/multiplayer_connect.hpp:1.25
--- wesnoth/src/multiplayer_connect.hpp:1.24    Sun Feb  6 10:40:12 2005
+++ wesnoth/src/multiplayer_connect.hpp Sun Feb 20 22:30:27 2005
@@ -1,7 +1,7 @@
-/* $Id: multiplayer_connect.hpp,v 1.24 2005/02/06 10:40:12 isaaccp Exp $ */
+/* $Id: multiplayer_connect.hpp,v 1.25 2005/02/20 22:30:27 gruikya Exp $ */
 /*
-   Copyright (C) 2003 by David White <address@hidden>
-   Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
+   Copyright (C) 
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License.
@@ -13,111 +13,223 @@
 #ifndef MULTIPLAYER_CONNECT_H_INCLUDED
 #define MULTIPLAYER_CONNECT_H_INCLUDED
 
-#include "multiplayer_lobby.hpp"
-#include "multiplayer_client.hpp"
-#include "network.hpp"
-#include "widgets/textbox.hpp"
-#include "widgets/button.hpp"
-#include "widgets/combo.hpp"
-#include "widgets/menu.hpp"
-#include "widgets/slider.hpp"
 #include "widgets/scrollpane.hpp"
-#include "widgets/label.hpp"
+#include "multiplayer_ui.hpp"
+#include "multiplayer_create.hpp"
+#include "config.hpp"
+#include "network.hpp"
+#include "leader_list.hpp"
 
-#include <deque>
-#include <iostream>
-#include <sstream>
 #include <string>
-#include <vector>
 
-class mp_connect : public lobby::dialog
-{
+namespace mp {
 
+class connect : public mp::ui
+{
 public:
-       mp_connect(display& disp, std::string game_name,
-                  const config &cfg, game_data& units_data,
-                  game_state& state, bool join = false,
-              const std::string& default_controller="ai");
-       ~mp_connect();
-
-       int load_map(const std::string& era, config& scenario, int num_turns, 
int village_gold, int xpmodifier,
-                    bool fog_game, bool shroud_game, bool allow_observers, 
bool share_view, bool share_maps);
+       struct connected_user {
+               connected_user(const std::string& name, mp::controller 
controller,
+                               network::connection connection) :
+                       name(name), controller(controller), 
connection(connection)
+               {};
+               std::string name;
+               mp::controller controller;
+               network::connection connection;
+       };
+
+       typedef std::vector<connected_user> connected_user_list;
+
+       class side {
+       public:
+               side(connect& parent, const config& cfg,
+                               int index, int default_gold,
+                               bool enabled = true);
+
+               side(const side& a);
+
+               void add_widgets_to_scrollpane(gui::scrollpane& pane, int pos);
+
+               void process_event();
+
+               // Returns true if this side changed since last call to 
changed()
+               bool changed();
+
+               // Gets a config object representing this side. If
+               // include_leader is set to true, the config objects include
+               // the "type=" defining the leader type, else it does not.
+               config get_config() const;
+
+               // Returns true if this side is waiting for a network player.
+               bool available() const;
+
+               // Sets the controller of a side.
+               void set_controller(mp::controller controller);
+               mp::controller get_controller() const;
+
+               // Adds an user to the user list combo
+               void update_user_list();
+
+               // Returns the username of this side
+               const std::string& get_id() const;
+               // Sets the username of this side
+               void set_id(const std::string& id);
+
+               const std::string& get_original_description() const;
+
+               // Imports data from the network into this side, and updates
+               // the UI accordingly.
+               void import_network_user(const config& data);
+
+               // Resets this side to its default state, and updates the UI
+               // accordingly.
+               void reset(mp::controller controller);
+
+               // Resolves the random leader / factions.
+               void resolve_random();
+
+       private:
+               void update_controller_ui();
+               void update_ui();
+
+               // The mp::connect widget owning this mp::connect::side. Used
+               // in the constructor, must be first.
+               connect* parent_; 
+
+               config cfg_;
+
+               // Configurable variables
+               int index_;
+               std::string id_;
+               std::string original_description_;
+               mp::controller controller_;
+               int faction_;
+               int team_;
+               int colour_;
+               int gold_;
+               std::string leader_;
+               //bool taken_;
+
+               // Widgets for this side
+               gui::label player_number_;
+               gui::combo combo_controller_;
+               gui::label orig_controller_;
+               gui::combo combo_faction_;
+               gui::combo combo_leader_;
+               gui::combo combo_team_;
+               gui::combo combo_colour_;
+               gui::slider slider_gold_;
+               gui::label label_gold_;
+
+               leader_list_manager llm_;
+
+               bool enabled_;
+               bool changed_;
+       };
+       typedef std::vector<side> side_list;
+
+
+       connect(display& disp, const config& game_config, const game_data& 
data, 
+                       chat& c, config& gamelist, const create::parameters& 
params, 
+                       mp::controller default_controller);
+
+       virtual void process_event();
+
+       // Returns the level data useful to play the game
+       const config& get_level();
+       const game_state& get_state();
 
+       // Updates the current level, resolves random factions, and sends a
+       // "start game" message to the network, with the current level
        void start_game();
 
-private:
-       virtual void set_area(const SDL_Rect& rect);
-       virtual void clear_area();
+protected:
+       virtual void layout_children(const SDL_Rect& rect);
 
-       lobby::RESULT process();
-       bool manages_network() const { return true; }
-       bool get_network_data(config& cfg);
-
-       void lists_init();
-       void gui_update();
-       void add_player(const std::string& name);
-       void remove_player(const std::string& name);
-       void update_positions();
-       void update_network();
-       bool is_full();
+       virtual void process_network_data(const config& data, const 
network::connection sock);
+       virtual void process_network_error(network::error& error);
+       virtual bool accept_connections();
+       virtual void process_network_connection(const network::connection sock);
 
-       size_t combo_index_to_team(size_t index) const;
+       virtual void hide_children(bool hide=true);
 
-       display *disp_;
+       virtual void gamelist_updated();
+private:
+       // Those 2 functions are actually the steps of the (complex)
+       // construction of this class. First, initialize default lists (for
+       // colours, sides, etc), then, load the game set the widgets values to
+       // the values given a the game creation step.
+       void lists_init(bool changes_allowes);
+       void load_game(const create::parameters& params);
+
+       // Updates the level_ variable to reflect the sides in the sides_ vector
+       void update_level();
+
+       // Returns true if there still are sides available for this game
+       bool sides_available();
+       
+       // Updates the state of the player list, the launch button and of the
+       // start game label, to reflect the actual state.
+       void update_playerlist_state();
+
+       // Returns the index of a player, from its id, or -1 if the player was 
not found
+       connected_user_list::iterator find_player(const std::string& id);
+
+       // Returns the side which is taken by a given player, or -1 if none was 
found.
+       int find_player_side(const std::string& id) const;
+
+       // Adds a player
+       void update_user_combos();
+
+       // Removes a player and kicks it from the game
+       void kick_player(const std::string& name);
+
+       // This is the main, and global, game data.
+       const game_data& game_data_;
+
+       // This is the configuration object which represents the level which
+       // will be generated by configuring this multiplayer game.
+       config level_;
+
+       // This is the "game state" object, which is constructed along with the
+       // "level" object
+       game_state state_;
 
+       // The era used for factions
        std::string era_;
 
-       const config *cfg_;
-       game_data *data_;
-       game_state *state_;
-       config *level_;
-
-       //the state the scenario is in before changes,
-       //so that we can generate a diff to send to clients
-       config old_level_;
-       std::map<config*,network::connection> positions_;
-
-       bool show_replay_;
-       bool save_;
-       int status_;
-       bool join_;
-
-       SDL_Rect rect_;
+       // The list of available sides for the current era
+       config::child_list era_sides_;
 
+       // Lists used for combos
        std::vector<std::string> player_types_;
-       std::vector<std::string> player_races_;
+       std::vector<std::string> player_factions_;
        std::vector<std::string> player_teams_;
-       std::vector<std::string> player_colors_;
+       std::vector<std::string> player_colours_;
 
-       //std::vector<std::vector<std::string> > player_leaders_;
-       std::vector<leader_list_manager> player_leaders_;
-       std::vector<std::string> possible_faction_ids_;
+       side_list sides_;
+       connected_user_list users_;
 
-       std::vector<std::string> team_names_;
-       std::vector<int> team_indices_;
+       gui::label waiting_label_;
+       bool message_full_;
+
+       controller default_controller_;
 
+       // Widgets
        gui::scrollpane scroll_pane_;
 
-       std::vector<gui::label> player_numbers_;
-       std::vector<gui::combo> combos_type_;
-       std::vector<gui::combo> combos_race_;
-       std::vector<gui::combo> combos_leader_;
-       std::vector<gui::combo> combos_team_;
-       std::vector<gui::combo> combos_color_;
-       std::vector<gui::slider> sliders_gold_;
-       std::vector<gui::label> labels_gold_;
+       gui::label type_title_label_;
+       gui::label faction_title_label_;
+       gui::label team_title_label_;
+       gui::label colour_title_label_;
+       gui::label gold_title_label_;
 
        gui::button ai_;
        gui::button launch_;
        gui::button cancel_;
 
-       gui::label waiting_label_;
-       bool message_full_;
-
-       std::deque<config> network_data_;
-
-       const std::string default_controller_;
-       const std::string team_prefix_;
 };
 
+}
+
 #endif
+
Index: wesnoth/src/multiplayer_lobby.cpp
diff -u wesnoth/src/multiplayer_lobby.cpp:1.57 
wesnoth/src/multiplayer_lobby.cpp:1.58
--- wesnoth/src/multiplayer_lobby.cpp:1.57      Fri Dec 31 21:01:37 2004
+++ wesnoth/src/multiplayer_lobby.cpp   Sun Feb 20 22:30:27 2005
@@ -1,453 +1,196 @@
-#include "global.hpp"
+/* $Id: multiplayer_lobby.cpp,v 1.58 2005/02/20 22:30:27 gruikya Exp $ */
+/*
+   Copyright (C) 
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
 
-#include "events.hpp"
+   See the COPYING file for more details.
+*/
+
+#include "multiplayer_lobby.hpp"
 #include "filesystem.hpp"
 #include "font.hpp"
-#include "game_config.hpp"
-#include "hotkeys.hpp"
-#include "image.hpp"
-#include "key.hpp"
-#include "language.hpp"
-#include "multiplayer_lobby.hpp"
-#include "network.hpp"
-#include "preferences.hpp"
-#include "show_dialog.hpp"
-#include "statistics.hpp"
-#include "sound.hpp"
 #include "wassert.hpp"
-#include "widgets/button.hpp"
-#include "widgets/menu.hpp"
-#include "widgets/textbox.hpp"
 
-#include "SDL.h"
+namespace mp {
 
-#include <sstream>
+lobby::lobby(display& disp, const config& cfg, chat& c, config& gamelist) :
+       mp::ui(disp, cfg, c, gamelist),
 
-namespace {
-int xscale(display& disp, int x)
+       observe_game_(disp, _("Observe Game")),
+       join_game_(disp, _("Join Game")),
+       create_game_(disp, _("Create Game")),
+       quit_game_(disp, _("Quit")),
+       games_menu_(disp, std::vector<std::string>()),
+       current_game_(0)
 {
-       return (x*disp.x())/1024;
+       gamelist_updated();
 }
 
-int yscale(display& disp, int y)
+void lobby::hide_children(bool hide)
 {
-       return (y*disp.y())/768;
+       mp::ui::hide_children(hide);
+
+       games_menu_.hide(hide);
+       observe_game_.hide(hide);
+       join_game_.hide(hide);
+       create_game_.hide(hide);
+       quit_game_.hide(hide);
 }
 
-const config* generate_game_options(const config& terrain_data, const config& 
game_data, int& game_selection,
-                                                           
std::vector<std::string>& options, std::vector<bool>& game_vacant_slots, 
std::vector<bool>& game_observers)
+void lobby::layout_children(const SDL_Rect& rect)
 {
-       const config* const gamelist = game_data.child("gamelist");
+       mp::ui::layout_children(rect);
 
-       // Game List GUI
-       if(gamelist == NULL) {
-               return gamelist;
-       }
+       join_game_.set_location(xscale(12),yscale(7));
+       observe_game_.set_location(join_game_.location().x + 
join_game_.location().w + 5,yscale(7));
+       create_game_.set_location(observe_game_.location().x + 
observe_game_.location().w + 5,yscale(7));
+       quit_game_.set_location(create_game_.location().x + 
create_game_.location().w + 5,yscale(7));
+
+       games_menu_.set_width(xscale(832));
+       games_menu_.set_location(xscale(12),yscale(42));
+}
 
-       options.clear();
-       game_vacant_slots.clear();
-       game_observers.clear();
+void lobby::gamelist_updated()
+{
+       ui::gamelist_updated();
 
-       config::const_child_itors i;
-       for(i = gamelist->child_range("game"); i.first != i.second; ++i.first) {
+       std::vector<std::string> game_strings;
+       const config* list = gamelist().child("gamelist");
+       if(list == NULL) {
+               // No gamelist yet. Do not update anything.
+               return;
+       }
+       config::child_list games = list->get_children("game");
+       config::child_iterator game;
+       game_observers_.clear();
+       game_vacant_slots_.clear();
 
-               std::cerr << "game data here:" << (**i.first).write() << "end 
game data here\n";
+       for(game = games.begin(); game != games.end(); ++game) {
 
                std::stringstream str;
 
-               //if this is the item that should be selected, make it selected 
by default
-               if(game_selection-- == 0) {
-                       str << DEFAULT_ITEM;
-               }
-
-               std::string map_data = (**i.first)["map_data"];
+               std::string map_data = (**game)["map_data"];
                if(map_data == "") {
-                       map_data = read_map((**i.first)["map"]);
+                       map_data = read_map((**game)["map"]);
                }
 
                if(map_data != "") {
                        try {
-                               gamemap map(terrain_data,map_data);
+                               gamemap map(game_config(), map_data);
                                const surface 
mini(image::getMinimap(100,100,map,0));
 
                                //generate a unique id to show the map as
                                char buf[50];
-                               sprintf(buf,"addr %p", (SDL_Surface*)mini);
+                               sprintf(buf,"addr %d",(int)(SDL_Surface*)mini);
 
                                image::register_image(buf,mini);
 
-                               str << IMAGE_PREFIX << buf << COLUMN_SEPARATOR;
+                               str << "&" << buf << COLUMN_SEPARATOR;
                        } catch(gamemap::incorrect_format_exception& e) {
                                std::cerr << "illegal map: " << e.msg_ << "\n";
                        }
                } else {
-                       str << '(' << _("Shroud") << ')' << COLUMN_SEPARATOR;
+                       str << "(" << _("Shroud") << ")" << COLUMN_SEPARATOR;
                }
 
-               std::string name = (**i.first)["name"];
-               if(name.size() > 30)
-                       name.resize(30);
-
-               str << name;
-
-               const std::string& turn = (**i.first)["turn"];
-               const std::string& slots = (**i.first)["slots"];
-               if (!turn.empty()) {
-                       str << COLUMN_SEPARATOR << _("Turn") << ' ' << turn;
-               } else if(!slots.empty()) {
-                       str << COLUMN_SEPARATOR << slots << ' '
-                           << gettext(slots == "1" ? N_("Vacant Slot") : 
N_("Vacant Slots"));
-               }
+               std::string name = (**game)["name"];
 
-               options.push_back(str.str());
-               game_vacant_slots.push_back(turn.empty() && slots != "" && 
slots != "0");
-               game_observers.push_back((**i.first)["observer"] != "no");
-       }
-
-       return gamelist;
-}
+               str << font::make_text_ellipsis(name, font::SIZE_NORMAL, 
xscale(300));
 
-void generate_user_list(const config& game_data, std::vector<std::string>& 
users, int& user_selection)
-{
-       users.clear();
+               const std::string& turn = (**game)["turn"];
+               const std::string& slots = (**game)["slots"];
+               int nslots = lexical_cast_default<int>(slots, 0);
 
-       for(config::const_child_itors i = game_data.child_range("user"); 
i.first != i.second; ++i.first) {
-               std::string name = (**i.first)["name"];
-               if(name.size() > 30)
-                       name.resize(30);
-
-               const std::string avail = (**i.first)["available"];
-
-               //display unavailable players in red
-               if(avail == "no") {
-                       name.insert(name.begin(),'#');
+               if(turn != "") {
+                       str << COLUMN_SEPARATOR << _("Turn") << " " << turn;
+               } else if(slots != "") {
+                       str << COLUMN_SEPARATOR << slots << " " << 
+                               ngettext(_("Vacant Slot"), _("Vacant Slots"), 
nslots);
                }
 
-               //if this user should be selected
-               if(user_selection-- == 0) {
-                       name.insert(name.begin(), DEFAULT_ITEM);
-               }
+               game_strings.push_back(str.str());
 
-               users.push_back(name);
+               game_vacant_slots_.push_back(slots != "" && slots != "0");
+               game_observers_.push_back((**game)["observer"] != "no");
        }
-}
-
-}
-
-namespace lobby {
-
-RESULT enter(display& disp, config& game_data, const config& terrain_data, 
dialog* dlg,
-                        std::vector<std::string>& messages)
-{
-       statistics::fresh_stats();
 
-       std::cerr << "entered multiplayer lobby...\n";
-       const preferences::display_manager disp_manager(&disp);
-       const hotkey::basic_handler key_handler(&disp);
-       const tooltips::manager tooltips_manager(disp);
-       disp.video().modeChanged(); // resets modeChanged value
-
-       CKey key;
-
-       surface background(image::get_image("misc/lobby.png",image::UNSCALED));
-       background.assign(scale_surface(background,disp.x(),disp.y()));
-
-       if(background == NULL) {
-               return QUIT;
+       if(game_strings.empty()) {
+               game_strings.push_back("<no games open>");
        }
 
-       SDL_BlitSurface(background, NULL, disp.video().getSurface(), NULL);
-       update_whole_screen();
-
-       gui::textbox message_entry(disp,500);
-
-       bool last_escape = true;
-
-       int game_selection = 0, user_selection = 0;
-
-       for(bool first_time = true; ; first_time = false) {
-               message_entry.set_focus(true);
-
-               const SDL_Rect dlg_rect = 
{xscale(disp,12),yscale(disp,42),xscale(disp,832),yscale(disp,518)};
-
-               //if the dialog is present, back it up before we repaint the 
entire screen
-               surface_restorer dlg_restorer;
-               if(dlg != NULL && first_time == false) {
-                       dlg_restorer = surface_restorer(&disp.video(),dlg_rect);
-               }
-
-               SDL_BlitSurface(background, NULL, disp.video().getSurface(), 
NULL);
+       games_menu_.set_items(game_strings);
 
-               dlg_restorer.restore();
-               dlg_restorer = surface_restorer();
-
-               const SDL_Rect chat_area = { xscale(disp,12), yscale(disp,576), 
xscale(disp,832), yscale(disp,142) };
-
-               gui::textbox chat_textbox(disp,chat_area.w,"",false);
-
-               std::vector<std::string> options;
-               std::vector<bool> game_vacant_slots, game_observers;
-
-               const config* gamelist = NULL;
-
-               if(dlg == NULL) {
-                       gamelist = 
generate_game_options(terrain_data,game_data,game_selection,options,game_vacant_slots,game_observers);
-                       if(gamelist == NULL) {
-                               std::cerr << "ERROR: could not find gamelist\n";
-                               return QUIT;
-                       }
-               }
-
-               if(dlg == NULL && options.empty()) {
-                       options.push_back(_("<no games open>"));
-               }
-
-               gui::menu games_menu(disp,options);
-               gui::button observe_game(disp,_("Observe Game"));
-               gui::button join_game(disp,_("Join Game"));
-               gui::button new_game(disp,_("Create Game"));
-               gui::button quit_game(disp,_("Quit"));
-
-               if(dlg != NULL) {
-                       observe_game.hide();
-                       join_game.hide();
-                       new_game.hide();
-                       quit_game.hide();
-               }
+       if(games_menu_.selection() >= 0 && games_menu_.selection() < 
int(game_vacant_slots_.size())) {
+               wassert(game_vacant_slots_.size() == game_observers_.size());
 
-               if(games_menu.selection() >= 0 && games_menu.selection() < 
int(game_vacant_slots.size())) {
-                       wassert(game_vacant_slots.size() == 
game_observers.size());
-
-                       
join_game.hide(!game_vacant_slots[games_menu.selection()]);
-                       
observe_game.hide(!game_observers[games_menu.selection()]);
-               } else {
-                       observe_game.hide();
-                       join_game.hide();
-               }
-               
-               std::vector<std::string> users;
-
-               generate_user_list(game_data,users,user_selection);
-
-               if(users.empty()) {
-                       users.push_back(preferences::login());
-               }
-
-               std::cerr << "have " << users.size() << " users\n";
-
-               if(users.empty()) {
-                       std::cerr << "ERROR: empty user list received\n";
-                       users.push_back("error");
-               }
-
-               gui::menu users_menu(disp,users);
-
-               games_menu.set_numeric_keypress_selection(false);
-               users_menu.set_numeric_keypress_selection(false);
+               observe_game_.enable(true);
+               join_game_.enable(true);
+               join_game_.hide(!game_vacant_slots_[games_menu_.selection()]);
+               observe_game_.hide(!game_observers_[games_menu_.selection()]);
+       } else {
+               observe_game_.enable(false);
+               join_game_.enable(false);
+       }
 
-               // Set GUI locations
-               users_menu.set_width(xscale(disp,156));
-               users_menu.set_location(xscale(disp,856),yscale(disp,42));
+}
 
-               
update_rect(xscale(disp,856),yscale(disp,42),xscale(disp,156),yscale(disp,708));
+void lobby::process_event()
+{
+       games_menu_.process();
 
-               if(dlg != NULL) {
-                       if(first_time) {
-                               dlg->set_area(dlg_rect);
-                       }
-               } else {
-                       games_menu.set_width(xscale(disp,832));
-                       
games_menu.set_location(xscale(disp,12),yscale(disp,42));
-               }
+       int selection = games_menu_.selection();
+       if(selection != current_game_ && selection >= 0 && selection < 
int(game_vacant_slots_.size())) {
+               current_game_ = selection;
+               join_game_.hide(!game_vacant_slots_[selection]);
+               observe_game_.hide(!game_observers_[selection]);
+       }
 
-               
update_rect(xscale(disp,12),yscale(disp,42),xscale(disp,832),yscale(disp,518));
-               join_game.set_location(xscale(disp,12),yscale(disp,7));
-               observe_game.set_location(join_game.location().x + 
join_game.location().w + 5,yscale(disp,7));
-               new_game.set_location(observe_game.location().x + 
observe_game.location().w + 5,yscale(disp,7));
-               quit_game.set_location(new_game.location().x + 
new_game.location().w + 5,yscale(disp,7));
-               message_entry.set_location(xscale(disp,14),yscale(disp,732));
-               message_entry.set_width(xscale(disp,830));
-
-               update_whole_screen();
-
-               bool old_enter = true;
-
-               size_t last_message = messages.size() < 50 ? 0 : 
messages.size() - 50;
-
-               for(;;) {
-
-                       if(last_message < messages.size()) {
-                               // Display Chats
-                               std::stringstream text;
-                               for(; last_message != messages.size(); 
++last_message) {
-                                       text << messages[last_message];
-                                       if(last_message+1 != messages.size()) {
-                                               text << "\n";
-                                       }
-                               }
-
-                               chat_textbox.append_text(text.str());
-
-                               chat_textbox.set_location(chat_area);
-                               chat_textbox.set_wrap(true);
-                               chat_textbox.scroll_to_bottom();
-                               chat_textbox.set_dirty();
-                       }
+       const bool games_available = game_vacant_slots_.empty() == false;
+       const bool double_click = games_menu_.double_clicked();
+       const bool observe = observe_game_.pressed() || !games_available && 
double_click;
+
+       if(games_available && (observe || join_game_.pressed() || 
double_click)) {
+               const size_t index = size_t(games_menu_.selection());
+               const config* game = gamelist().child("gamelist");
+               if (game != NULL) {
+                       const config::const_child_itors i = 
game->child_range("game");
+                       wassert(index < size_t(i.second - i.first));
+                       const std::string& id = (**(i.first+index))["id"];
+
+                       config response;
+                       config& join = response.add_child("join");
+                       join["id"] = id;
+                       network::send_data(response);
 
-                       int mousex, mousey;
-                       SDL_GetMouseState(&mousex,&mousey);
-                       tooltips::process(mousex, mousey);
-
-                       if(dlg != NULL) {
-                               const RESULT res = dlg->process();
-                               if(res != CONTINUE) {
-                                       return res;
-                               }
+                       if (observe) {
+                               set_result(OBSERVE);
                        } else {
-                               games_menu.process();
-
-                               if(games_menu.selection() >= 0 && 
games_menu.selection() < int(game_vacant_slots.size())) {
-                                       
join_game.hide(!game_vacant_slots[games_menu.selection()]);
-                                       
observe_game.hide(!game_observers[games_menu.selection()]);
-                               }
-                       }
-
-                       users_menu.process();
-                       
-                       const bool games_available = game_vacant_slots.empty() 
== false;
-                       const bool double_click = games_menu.double_clicked();
-                       const bool observe = observe_game.pressed() || 
games_available && double_click && join_game.hidden();
-                       if(games_available && (observe || join_game.pressed() 
|| double_click)) {
-                               const size_t index = 
size_t(games_menu.selection());
-                               const config::const_child_itors i = 
gamelist->child_range("game");
-                               wassert(index < size_t(i.second - i.first));
-                               const std::string& id = 
(**(i.first+index))["id"];
-
-                               config response;
-                               config& join = response.add_child("join");
-                               join["id"] = id;
-                               network::send_data(response);
-                               return observe ? OBSERVE : JOIN;
+                               set_result(JOIN);
                        }
+               }
+               return;
+       }
                        
-                       if(dlg == NULL && new_game.pressed()) {
-                               return CREATE;
-                               break;
-                       }
-
-                       const bool enter = key[SDLK_RETURN] && !old_enter;
-                       old_enter = key[SDLK_RETURN] != 0;
-                       if(enter && message_entry.text().empty() == false) {
-                               const std::string& text = message_entry.text();
-
-                               static const std::string query = "/query ";
-                               if(text.size() >= query.size() && 
std::equal(query.begin(),query.end(),text.begin())) {
-                                       const std::string args = 
text.substr(query.size());
-
-                                       config cfg;
-                                       cfg.add_child("query")["type"] = args;
-                                       network::send_data(cfg);
-                               } else {
-
-                                       config msg;
-                                       config& child = 
msg.add_child("message");
-                                       child["message"] = text;
-                                       child["sender"] = preferences::login();
-                                       network::send_data(msg);
-
-                                       std::stringstream message;
-                                       message << "<" << child["sender"] << "> 
 " << child["message"];
-                                       messages.push_back(message.str());
-                               }
-
-                               message_entry.clear();
-                       }
-
-                       if(last_escape == false && key[SDLK_ESCAPE] || dlg == 
NULL && quit_game.pressed()){
-                               return QUIT;
-                       }
-
-                       last_escape = key[SDLK_ESCAPE] != 0;
-
-                       events::raise_process_event();
-                       events::raise_draw_event();
-
-                       chat_textbox.process();
-
-                       user_selection = users_menu.selection();
-                       game_selection = games_menu.selection();
-
-                       //if the list is refreshed, we want to redraw the 
entire screen
-                       config data;
-                       bool got_data = false;
-                       if(dlg == NULL || dlg->manages_network() == false) {
-                               const network::connection res = 
network::receive_data(data);
-                               if(res) {
-                                       got_data = true;
-                               }
-                       } else if(dlg != NULL && dlg->manages_network()) {
-                               got_data = dlg->get_network_data(data);
-                       }
+       if(create_game_.pressed()) {
+               set_result(CREATE);
+               return;
+       }
 
-                       if(got_data) {
-                               if(data.child("gamelist")) {
-                                       game_data = data;
-                                       break;
-                               } else if(data.child("gamelist_diff")) {
-                                       const config old_gamelist = 
game_data.child("gamelist") != NULL ? *game_data.child("gamelist") : config();
-
-                                       const int old_users = 
game_data.get_children("user").size();
-                                       
game_data.apply_diff(*data.child("gamelist_diff"));
-                                       const int new_users = 
game_data.get_children("user").size();
-
-                                       const config new_gamelist = 
game_data.child("gamelist") != NULL ? *game_data.child("gamelist") : config();
-                                       if(new_users < old_users) {
-                                               
sound::play_sound(game_config::sounds::user_leave);
-                                       } else if(new_users > old_users) {
-                                               
sound::play_sound(game_config::sounds::user_arrive);
-                                       }
-
-                                       
generate_user_list(game_data,users,user_selection);
-                                       users_menu.set_items(users);
-
-                                       gamelist = game_data.child("gamelist");
-                                       if(gamelist == NULL) {
-                                               std::cerr << "ERROR: could not 
find game list\n";
-                                               return QUIT;
-                                       }
-
-                                       if(dlg == NULL && *gamelist != 
old_gamelist) {
-                                               
generate_game_options(terrain_data,game_data,game_selection,options,game_vacant_slots,game_observers);
-                                       }
-
-                                       if(dlg == NULL && options.empty()) {
-                                               options.push_back(_("<no games 
open>"));
-                                       }
-
-                                       games_menu.set_items(options);
-                               } else if(data.child("error")) {
-                                       throw 
network::error((*data.child("error"))["message"]);
-                               } else if(data.child("message")) {
-                                       
sound::play_sound(game_config::sounds::receive_message);
-
-                                       const config& msg = 
*data.child("message");
-                                       std::stringstream message;
-                                       message << "<" << msg["sender"] << ">  
" << msg["message"];
-                                       messages.push_back(message.str());
-                               }
-                       }
+       if(quit_game_.pressed()) {
+               set_result(QUIT);
+               return;
+       }
+}
 
-                       if(disp.video().modeChanged()) {
-                               if (dlg != NULL)
-                                       dlg->clear_area();
-                               return CONTINUE;
-                       }
 
-                       events::pump();
-                       disp.video().flip();
-                       SDL_Delay(20);
-               }
-       }
+void lobby::process_network_data(const config& data, const network::connection 
sock)
+{
+       ui::process_network_data(data, sock);
 }
 
 }
Index: wesnoth/src/multiplayer_lobby.hpp
diff -u wesnoth/src/multiplayer_lobby.hpp:1.8 
wesnoth/src/multiplayer_lobby.hpp:1.9
--- wesnoth/src/multiplayer_lobby.hpp:1.8       Mon Nov  1 18:06:36 2004
+++ wesnoth/src/multiplayer_lobby.hpp   Sun Feb 20 22:30:27 2005
@@ -1,32 +1,55 @@
-#ifndef MULTIPLAYER_LOBBY_INCLUDED
-#define MULTIPLAYER_LOBBY_INCLUDED
+/* $Id: multiplayer_lobby.hpp,v 1.9 2005/02/20 22:30:27 gruikya Exp $ */
+/*
+   Copyright (C) 
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef MULTIPLAYER_LOBBY_HPP_INCLUDED
+#define MULTIPLAYER_LOBBY_HPP_INCLUDED
 
 #include "config.hpp"
 #include "display.hpp"
+#include "multiplayer_ui.hpp"
+
+#include "widgets/menu.hpp"
 
-///this module controls the multiplayer lobby. A section on the server which
-///allows players to chat, create games, and join games.
-namespace lobby {
-
-enum RESULT { QUIT, CREATE, JOIN, OBSERVE, CONTINUE };
-
-///interface for an interactive dialog that is displayed while lobby user lists
-///and lobby chat continue
-class dialog
+// This module controls the multiplayer lobby. A section on the server which
+// allows players to chat, create games, and join games.
+namespace mp {
+
+class lobby : public ui
 {
 public:
-       virtual void set_area(const SDL_Rect& area) = 0;
-       virtual void clear_area() {};
-       virtual RESULT process() = 0;
-       virtual bool manages_network() const { return false; }
-       virtual bool get_network_data(config& out) { return false; }
-       virtual ~dialog() {}
-};
+       lobby(display& d, const config& cfg, chat& c, config& gamelist);
+
+       virtual void process_event();
 
-///function which controls the lobby, and will result in the player creating
-///a game, joining a game, or quitting the lobby.
-RESULT enter(display& disp, config& data, const config& terrain_data, dialog* 
dlg,
-                        std::vector<std::string>& messages);
+protected:
+       virtual void hide_children(bool hide=true);
+       virtual void layout_children(const SDL_Rect& rect);
+       virtual void process_network_data(const config& data, const 
network::connection sock);
+
+       virtual void gamelist_updated();
+private:
+
+       std::vector<bool> game_vacant_slots_;
+       std::vector<bool> game_observers_;
+
+       gui::button observe_game_;
+       gui::button join_game_;
+       gui::button create_game_;
+       gui::button quit_game_;
+
+       gui::menu games_menu_;
+       int current_game_;
+};
 
 }
 
Index: wesnoth/src/server/game.cpp
diff -u wesnoth/src/server/game.cpp:1.28 wesnoth/src/server/game.cpp:1.29
--- wesnoth/src/server/game.cpp:1.28    Tue Feb  8 12:29:31 2005
+++ wesnoth/src/server/game.cpp Sun Feb 20 22:30:29 2005
@@ -136,6 +136,7 @@
 
                                const bool res = take_side(player,new_cfg);
 
+#if 0
                                //if there's another side available, then tell 
the player that they've
                                //had their side reassigned
                                if(res) {
@@ -145,6 +146,7 @@
                                        reassign["to"] = new_cfg["side"];
                                        network::queue_data(response,player);
                                }
+#endif
 
                                return res;
                        }
@@ -162,6 +164,40 @@
        return true;
 }
 
+void game::update_side_data()
+{
+       sides_taken_.clear();
+       sides_.clear();
+       
+       const config::child_itors level_sides = level_.child_range("side");
+
+       //for each player:
+       // * Find the player name
+       // * Find the side this player name corresponds to
+       for(std::vector<network::connection>::const_iterator player = 
players_.begin();
+                       player != players_.end(); ++player) {
+
+               player_map::const_iterator info = player_info_->find(*player);
+               if (info == player_info_->end()) {
+                       std::cerr << "Error: unable to find player info for 
connection " << *player << "\n";
+                       continue;
+               }
+
+               config::child_iterator sd;
+               for(sd = level_sides.first; sd != level_sides.second; ++sd) {
+                       if ((**sd)["id"] == info->second.name()) {
+                               break;
+                       }
+               }
+
+               if (sd != level_sides.second) {
+                       //this user has a side. Updates the variables 
accordingly.
+                       sides_taken_.insert((**sd)["side"]);
+                       sides_[*player] = (**sd)["side"];
+               }
+       }
+}
+
 const std::string& game::transfer_side_control(const config& cfg)
 {
        const std::string& player = cfg["player"];
@@ -231,16 +267,16 @@
 
 size_t game::available_slots() const
 {
-       size_t total_slots = 0;
+       size_t available_slots = 0;
        const config::child_list& sides = level_.get_children("side");
        for(config::child_list::const_iterator i = sides.begin(); i != 
sides.end(); ++i) {
                std::cerr << "side controller: '" << (**i)["controller"] << 
"'\n";
-               if((**i)["controller"] == "network") {
-                       ++total_slots;
+               if((**i)["controller"] == "network" && (**i)["id"].empty()) {
+                       ++available_slots;
                }
        }
 
-       return total_slots - sides_taken_.size();
+       return available_slots;
 }
 
 bool game::describe_slots()
@@ -378,7 +414,7 @@
        network::queue_data(history_,player);
 }
 
-void game::remove_player(network::connection player)
+void game::remove_player(network::connection player, bool notify_creator)
 {
        const std::vector<network::connection>::iterator itor =
                     std::find(players_.begin(),players_.end(),player);
@@ -389,7 +425,7 @@
        std::map<network::connection,std::string>::iterator side = 
sides_.find(player);
        if(side != sides_.end()) {
                //send the host a notification of removal of this side
-               if(players_.empty() == false) {
+               if(notify_creator && players_.empty() == false) {
                        config drop;
                        drop["side_drop"] = side->second;
                        network::queue_data(drop,players_.front());
Index: wesnoth/src/server/game.hpp
diff -u wesnoth/src/server/game.hpp:1.16 wesnoth/src/server/game.hpp:1.17
--- wesnoth/src/server/game.hpp:1.16    Sun Oct 31 15:21:04 2004
+++ wesnoth/src/server/game.hpp Sun Feb 20 22:30:29 2005
@@ -35,6 +35,8 @@
 
        bool take_side(network::connection player, const config& cfg);
 
+       void update_side_data();
+
        const std::string& transfer_side_control(const config& cfg);
        
        size_t available_slots() const;
@@ -47,7 +49,7 @@
        void ban_player(network::connection player);
 
        void add_player(network::connection player);
-       void remove_player(network::connection player);
+       void remove_player(network::connection player, bool 
notify_creator=true);
 
        int id() const;
 
Index: wesnoth/src/server/server.cpp
diff -u wesnoth/src/server/server.cpp:1.65 wesnoth/src/server/server.cpp:1.66
--- wesnoth/src/server/server.cpp:1.65  Sun Feb 20 21:45:22 2005
+++ wesnoth/src/server/server.cpp       Sun Feb 20 22:30:29 2005
@@ -64,13 +64,13 @@
 public:
        server(int port, input_stream& input);
        void run();
-private:
-       void process_data(network::connection sock, config& data, config& 
gamelist);
-
-       void process_login(network::connection sock, const config& data, 
config& gamelist);
-       void process_query(network::connection sock, const config& query, 
config& gamelist);
-       void process_data_from_player_in_lobby(network::connection sock, 
config& data, config& gamelist);
-       void process_data_from_player_in_game(network::connection sock, config& 
data, config& gamelist);
+private:
+       void process_data(network::connection sock, config& data, config& 
gamelist);
+
+       void process_login(network::connection sock, const config& data, 
config& gamelist);
+       void process_query(network::connection sock, const config& query, 
config& gamelist);
+       void process_data_from_player_in_lobby(network::connection sock, 
config& data, config& gamelist);
+       void process_data_from_player_in_game(network::connection sock, config& 
data, config& gamelist);
 
        void process_command(const std::string& cmd);
 
@@ -82,6 +82,7 @@
        const network::server_manager server_;
 
        config login_response_;
+       config join_lobby_response_;
 
        config initial_response_;
        config old_initial_response_;
@@ -109,6 +110,8 @@
 {
        login_response_.add_child("mustlogin");
        login_response_["version"] = game_config::version;
+
+       join_lobby_response_.add_child("join_lobby");
 }
 
 bool server::is_ip_banned(const std::string& ip)
@@ -285,8 +288,7 @@
 
                        config data;
                        while((sock = network::receive_data(data)) != 
network::null_connection) {
-
-                               metrics_.service_request();
+                               metrics_.service_request();
                                process_data(sock,data,gamelist);
                        }
 
@@ -339,489 +341,509 @@
                SDL_Delay(20);
        }
 }
-
-void server::process_data(const network::connection sock, config& data, 
config& gamelist)
-{
-       //if someone who is not yet logged in is sending
-       //login details
-       if(not_logged_in_.is_member(sock)) {
-               process_login(sock,data,gamelist);
-       } else if(const config* query = data.child("query")) {
-               process_query(sock,*query,gamelist);
-       } else if(lobby_players_.is_member(sock)) {
-               process_data_from_player_in_lobby(sock,data,gamelist);
-       } else {
-               process_data_from_player_in_game(sock,data,gamelist);
-       }
-}
-
-void server::process_login(const network::connection sock, const config& data, 
config& gamelist)
-{
-       const config* const login = data.child("login");
-
-       //client must send a login first.
-       if(login == NULL) {
-               network::send_data(construct_error(
-                                  "You must login first"),sock);
-               return;
-       }
-
-       //check the username is valid (all alpha-numeric or space)
-       std::string username = (*login)["username"];
-       utils::strip(username);
-       const int alnum = 
std::count_if(username.begin(),username.end(),isalnum);
-       const int spaces = std::count(username.begin(),username.end(),' ');
-       if((alnum + spaces != username.size()) || spaces == username.size() || 
username.empty()) {
-               network::send_data(construct_error(
-                                  "This username is not valid"),sock);
-               return;
-       }
-
-       if(username.size() > 32) {
-               network::send_data(construct_error(
-                                  "This username is too long"),sock);
-               return;
-       }
-
-       if(username == "server") {
-               network::send_data(construct_error(
-                                  "The nick 'server' is reserved and can not 
be used by players"),sock);
-               return;
-       }
-
-       //check the username isn't already taken
-       player_map::const_iterator p;
-       for(p = players_.begin(); p != players_.end(); ++p) {
-               if(p->second.name() == username) {
-                       break;
-               }
-       }
-
-       if(p != players_.end()) {
-               network::send_data(construct_error(
-                             "This username is already taken"),sock);
-               return;
-       }
-       
-       config* const player_cfg = &initial_response_.add_child("user");
-
-       const player new_player(username,*player_cfg);
-
-       players_.insert(std::pair<network::connection,player>(sock,new_player));
-
-       //remove player from the not-logged-in list and place
-       //the player in the lobby
-       not_logged_in_.remove_player(sock);
-       lobby_players_.add_player(sock);
-
-       //send the new player the entire list of games and players
-       network::send_data(initial_response_,sock);
-
-       //send other players in the lobby the update that the player has joined
-       lobby_players_.send_data(sync_initial_response(),sock);
-
-       std::cerr << "'" << username << "' (" << network::ip_address(sock) << 
") has logged on\n";
-
-       for(std::vector<game>::iterator g = games_.begin(); g != games_.end(); 
++g) {
-               g->send_data_observers(construct_server_message(username + " 
has logged into the lobby",*g));
-       }
-}
-
-void server::process_query(const network::connection sock, const config& 
query, config& gamelist)
-{
-       //process queries from clients in here
-       std::ostringstream response;
-       if(query["type"] == "metrics") {
-               //a query for server data from a player
-               response << metrics_;   
-       } else {
-               response << "Error: unrecognized query";
-       }
-               
-       
network::send_data(construct_server_message(response.str(),lobby_players_),sock);
-}
-
-void server::process_data_from_player_in_lobby(const network::connection sock, 
config& data, config& gamelist)
-{
-       const config* const create_game = data.child("create_game");
-       if(create_game != NULL) {
-
-               std::cerr << "creating game...\n";
-
-               //create the new game, remove the player from the
-               //lobby and put him/her in the game they have created
-               games_.push_back(game(players_));
-               lobby_players_.remove_player(sock);
-               games_.back().add_player(sock);
-
-               //store the game data here at the moment
-               games_.back().level() = *create_game;
-               std::stringstream converter;
-               converter << games_.back().id();
-               games_.back().level()["id"] = converter.str();
-
-               //mark the player as unavailable in the lobby
-               const player_map::iterator pl = players_.find(sock);
-               if(pl != players_.end()) {
-                       pl->second.mark_available(false);
-
-                       lobby_players_.send_data(sync_initial_response());
-               } else {
-                       std::cerr << "ERROR: Could not find player in map\n";
-               }
-
-               return;
-       }
-
-       //see if the player is joining a game
-       const config* const join = data.child("join");
-       if(join != NULL) {
-               const std::string& id = (*join)["id"];
-               const int nid = atoi(id.c_str());
-               const std::vector<game>::iterator it =
-                            std::find_if(games_.begin(),games_.end(),
-                                         game_id_matches(nid));
-               if(it == games_.end()) {
-                       //send a response saying the game has been cancelled
-                       config cfg;
-                       cfg.add_child("leave_game");
-                       network::send_data(cfg,sock);
-
-                       std::cerr << "attempt to join unknown game\n";
-                       return;
-               }
-
-               if(it->player_is_banned(sock)) {
-                       network::send_data(construct_error("You are banned from 
this game"),sock);
-                       return;
-               }
-
-               lobby_players_.remove_player(sock);
-
-               //send them the game data
-               network::send_data(it->level(),sock);
-
-               it->add_player(sock);
-
-               //mark the player as unavailable in the lobby
-               const player_map::iterator pl = players_.find(sock);
-               if(pl != players_.end()) {
-                       pl->second.mark_available(false);
-
-                       lobby_players_.send_data(sync_initial_response());
-               } else {
-                       std::cerr << "ERROR: Could not find player in map\n";
-               }
-       }
-
-       //see if it's a message, in which case we add the name
-       //of the sender, and forward it to all players in the lobby
-       config* const message = data.child("message");
-       if(message != NULL) {
-               const player_map::const_iterator p = players_.find(sock);
-               wassert(p != players_.end());
-               (*message)["sender"] = p->second.name();
-
-               truncate_message((*message)["message"]);
-
-               lobby_players_.send_data(data,sock);
-       }
-}
-
-void server::process_data_from_player_in_game(const network::connection sock, 
config& data, config& gamelist)
-{
-       std::vector<game>::iterator g;
-       for(g = games_.begin(); g != games_.end(); ++g) {
-               if(g->is_member(sock))
-                       break;
-       }
-
-       if(g == games_.end()) {
-               std::cerr << "ERROR: unknown socket " << games_.size() << "\n";
-               return;
-       }
-
-       //if info is being provided about the game state
-       if(data.child("info") != NULL) {
-               const config& info = *data.child("info");
-               if(info["type"] == "termination") {
-                       g->set_termination_reason(info["condition"]);
-               }
-       }
-
-       //if the owner is changing the controller for a side
-       if(g->is_owner(sock) && data.child("change_controller") != NULL) {
-               const config& change = *data.child("change_controller");
-               const std::string& result = g->transfer_side_control(change);
-               if(result == "") {
-                       const config& msg = 
construct_server_message(change["player"] + " takes control of side " + 
change["side"],*g);
-                       g->send_data(msg);
-               } else {
-                       const config& msg = construct_server_message(result,*g);
-                       network::send_data(msg,sock);
-               }
-
-               return;
-       }
-
-       //if the owner is banning someone from the game
-       if(g->is_owner(sock) && data.child("ban") != NULL) {
-               const config& ban = *data.child("ban");
-               const std::string& name = ban["username"];
-               player_map::iterator pl;
-               for(pl = players_.begin(); pl != players_.end(); ++pl) {
-                       if(pl->second.name() == name) {
-                               break;
-                       }
-               }
-
-               if(pl->first != sock && pl != players_.end()) {
-                       g->ban_player(pl->first);
-                       const config& msg = construct_server_message("You have 
been banned",*g);
-                       network::send_data(msg,pl->first);
-                       config leave_game;
-                       leave_game.add_child("leave_game");
-                       network::send_data(leave_game,pl->first);
-
-                       g->describe_slots();
-                       lobby_players_.add_player(pl->first);
-
-                       //mark the player as available in the lobby
-                       pl->second.mark_available(true);
-
-                       //send the player who was banned the lobby game list
-                       network::send_data(initial_response_,pl->first);
-
-                       //send all other players in the lobby the update to the 
lobby
-                       lobby_players_.send_data(sync_initial_response(),sock);
-               } else if(pl == players_.end()) {
-                       const config& response = construct_server_message(
-                                    "Ban failed: user '" + name + "' not 
found",*g);
-                       network::send_data(response,sock);
-               }
-       } else if(data.child("ban")) {
-               const config& response = construct_server_message(
-                            "You cannot ban: not the game creator",*g);
-               network::send_data(response,sock);
-       }
-
-       //if this is data describing changes to a game.
-       else if(g->is_owner(sock) && data.child("scenario_diff")) {
-               g->level().apply_diff(*data.child("scenario_diff"));
-               g->send_data(data,sock);
-
-               const bool lobby_changes = g->describe_slots();
-               if(lobby_changes) {
-                       lobby_players_.send_data(sync_initial_response());
-               }
-       }
-
-       //if this is data describing the level for a game.
-       else if(g->is_owner(sock) && data.child("side") != NULL) {
-
-               const bool is_init = g->level_init();
-
-               //if this game is having its level data initialized
-               //for the first time, and is ready for players to join.
-               //We should currently have a summary of the game in g->level().
-               //we want to move this summary to the initial_response_, and
-               //place a pointer to that summary in the game's description.
-               //g->level() should then receive the full data for the game.
-               if(!is_init) {
-
-                       //if there is no shroud, then tell players in the lobby 
what the map looks like
-                       if((*data.child("side"))["shroud"] != "yes") {
-                               g->level().values["map_data"] = 
data["map_data"];
-                               g->level().values["map"] = data["map"];
-                       }
-                       
-                       //update our config object which describes the
-                       //open games, and notifies the game of where its 
description
-                       //is located at
-                       config& desc = gamelist.add_child("game",g->level());
-                       g->set_description(&desc);
-
-                       //record the full description of the scenario in 
g->level()
-                       g->level() = data;
-                       g->describe_slots();
-
-                       //send all players in the lobby the update to the list 
of games
-                       lobby_players_.send_data(sync_initial_response());
-               } else {
-
-                       //we've already initialized this scenario, but clobber 
its old
-                       //contents with the new ones given here
-                       g->level() = data;
-               }
-
-               //send all players in the level, except the sender, the new data
-               g->send_data(data,sock);
-               return;
-       }
-
-       const string_map::const_iterator side = data.values.find("side");
-       if(side != data.values.end()) {
-               const bool res = g->take_side(sock,data);
-               config response;
-               if(res) {
-                       std::cerr << "played joined side\n";
-                       response["side_secured"] = side->second;
-
-                       //update the number of available slots
-                       const bool res = g->describe_slots();
-                       if(res) {
-                               
lobby_players_.send_data(sync_initial_response());
-                       }
-               } else {
-                       response["failed"] = "yes";
-               }
-
-               network::send_data(response,sock);
-               return;
-       }
-
-       if(data.child("start_game")) {
-               //send notification of the game starting immediately.
-               //g->start_game() will send data that assumes the [start_game]
-               //message has been sent
-               g->send_data(data,sock);
-
-               g->start_game();
-               lobby_players_.send_data(sync_initial_response());
-               return;
-       } else if(data.child("leave_game")) {
-               const bool needed = g->is_needed(sock);
-
-               if(needed) {
-
-                       //tell all other players the game is over,
-                       //because a needed player has left
-                       config cfg;
-                       cfg.add_child("leave_game");
-                       g->send_data(cfg);
-
-                       //delete the game's description
-                       config* const gamelist = 
initial_response_.child("gamelist");
-                       wassert(gamelist != NULL);
-                       const config::child_itors vg = 
gamelist->child_range("game");
-
-                       const config::child_iterator desc = 
std::find(vg.first,vg.second,g->description());
-                       if(desc != vg.second) {
-                               gamelist->remove_child("game",desc - vg.first);
-                       }
-
-                       //update the state of the lobby to players in it.
-                       //We have to sync the state of the lobby so we can
-                       //send it to the players leaving the game
-                       lobby_players_.send_data(sync_initial_response());
-
-                       //set the availability status for all quitting players
-                       for(player_map::iterator pl = players_.begin(); pl != 
players_.end(); ++pl) {
-                               if(g->is_member(pl->first)) {
-                                       pl->second.mark_available(true);
-                               }
-                       }
-
-                       //put the players back in the lobby and send
-                       //them the game list and user list again
-                       g->send_data(initial_response_);
-                       metrics_.game_terminated(g->termination_reason());
-                       lobby_players_.add_players(*g);
-                       games_.erase(g);
-
-                       //now sync players in the lobby again, to remove the 
game
-                       lobby_players_.send_data(sync_initial_response());
-               } else {
-
-                       g->remove_player(sock);
-                       g->describe_slots();
-                       lobby_players_.add_player(sock);
-
-                       //mark the player as available in the lobby
-                       const player_map::iterator pl = players_.find(sock);
-                       if(pl != players_.end()) {
-                               pl->second.mark_available(true);
-                       } else {
-                               std::cerr << "ERROR: Could not find player in 
map\n";
-                       }
-
-                       //send the player who has quit the game list
-                       network::send_data(initial_response_,sock);
-
-                       //send all other players in the lobby the update to the 
lobby
-                       lobby_players_.send_data(sync_initial_response(),sock);
-               }
-
-               return;
-       } else if(data["side_secured"].empty() == false) {
-               return;
-       } else if(data["failed"].empty() == false) {
-               std::cerr << "ERROR: failure to get side\n";
-               return;
-       }
-
-       config* const turn = data.child("turn");
-       if(turn != NULL) {
-               g->filter_commands(sock,*turn);
-
-               //notify the game of the commands, and if it changes
-               //the description, then sync the new description
-               //to players in the lobby
-               const bool res = g->process_commands(*turn);
-               if(res) {
-                       lobby_players_.send_data(sync_initial_response());
-               }
-
-               //any private 'speak' commands must be repackaged seperate
-               //to other commands, and re-sent, since they should only go
-               //to some clients.
-               const config::child_itors speaks = turn->child_range("command");
-               int npublic = 0, nprivate = 0, nother = 0;
-               std::string team_name;
-               for(config::child_iterator i = speaks.first; i != 
speaks.second; ++i) {
-                       config* const speak = (*i)->child("speak");
-                       if(speak == NULL) {
-                               ++nother;
-                               continue;
-                       }
-
-                       truncate_message((*speak)["message"]);
-
-                       //force the description to be correct to prevent
-                       //spoofing of messages
-                       const player_map::const_iterator pl = 
players_.find(sock);
-                       wassert(pl != players_.end());
-                       (*speak)["description"] = pl->second.name();
-
-                       if((*speak)["team_name"] == "") {
-                               ++npublic;
-                       } else {
-                               ++nprivate;
-                               team_name = (*speak)["team_name"];
-                       }
-               }
-
-               //if all there are are messages and they're all private, then
-               //just forward them on to the client that should receive them.
-               if(nprivate > 0 && npublic == 0 && nother == 0) {
-                       g->send_data_team(data,team_name,sock);
-                       return;
-               }
-
-               //at the moment, if private messages are mixed in with other
-               //data, then let them go through. It's exceedingly unlikely that
-               //this will happen anyway, and if it does, the client should
-               //respect not displaying the message.
-       }
-
-       //forward data to all players who are in the game,
-       //except for the original data sender
-       g->send_data(data,sock);
-
-       if(g->started()) {
-               g->record_data(data);
-       }
-}
+
+void server::process_data(const network::connection sock, config& data, 
config& gamelist)
+{
+       //if someone who is not yet logged in is sending
+       //login details
+       if(not_logged_in_.is_member(sock)) {
+               process_login(sock,data,gamelist);
+       } else if(const config* query = data.child("query")) {
+               process_query(sock,*query,gamelist);
+       } else if(lobby_players_.is_member(sock)) {
+               process_data_from_player_in_lobby(sock,data,gamelist);
+       } else {
+               process_data_from_player_in_game(sock,data,gamelist);
+       }
+}
+
+void server::process_login(const network::connection sock, const config& data, 
config& gamelist)
+{
+       const config* const login = data.child("login");
+
+       //client must send a login first.
+       if(login == NULL) {
+               network::send_data(construct_error(
+                                  "You must login first"),sock);
+               return;
+       }
+
+       //check the username is valid (all alpha-numeric or space)
+       std::string username = (*login)["username"];
+       utils::strip(username);
+       const int alnum = 
std::count_if(username.begin(),username.end(),isalnum);
+       const int spaces = std::count(username.begin(),username.end(),' ');
+       if((alnum + spaces != username.size()) || spaces == username.size() || 
username.empty()) {
+               network::send_data(construct_error(
+                                  "This username is not valid"),sock);
+               return;
+       }
+
+       if(username.size() > 32) {
+               network::send_data(construct_error(
+                                  "This username is too long"),sock);
+               return;
+       }
+
+       if(username == "server") {
+               network::send_data(construct_error(
+                                  "The nick 'server' is reserved and can not 
be used by players"),sock);
+               return;
+       }
+
+       //check the username isn't already taken
+       player_map::const_iterator p;
+       for(p = players_.begin(); p != players_.end(); ++p) {
+               if(p->second.name() == username) {
+                       break;
+               }
+       }
+
+       if(p != players_.end()) {
+               network::send_data(construct_error(
+                             "This username is already taken"),sock);
+               return;
+       }
+       
+       network::send_data(join_lobby_response_, sock);
+
+       config* const player_cfg = &initial_response_.add_child("user");
+
+       const player new_player(username,*player_cfg);
+
+       players_.insert(std::pair<network::connection,player>(sock,new_player));
+
+       //remove player from the not-logged-in list and place
+       //the player in the lobby
+       not_logged_in_.remove_player(sock);
+       lobby_players_.add_player(sock);
+
+       //send the new player the entire list of games and players
+       network::send_data(initial_response_,sock);
+
+       //send other players in the lobby the update that the player has joined
+       lobby_players_.send_data(sync_initial_response(),sock);
+
+       std::cerr << "'" << username << "' (" << network::ip_address(sock) << 
") has logged on\n";
+
+       for(std::vector<game>::iterator g = games_.begin(); g != games_.end(); 
++g) {
+               g->send_data_observers(construct_server_message(username + " 
has logged into the lobby",*g));
+       }
+}
+
+void server::process_query(const network::connection sock, const config& 
query, config& gamelist)
+{
+       //process queries from clients in here
+       std::ostringstream response;
+       if(query["type"] == "metrics") {
+               //a query for server data from a player
+               response << metrics_;   
+       } else {
+               response << "Error: unrecognized query";
+       }
+               
+       
network::send_data(construct_server_message(response.str(),lobby_players_),sock);
+}
+
+void server::process_data_from_player_in_lobby(const network::connection sock, 
config& data, config& gamelist)
+{
+       const config* const create_game = data.child("create_game");
+       if(create_game != NULL) {
+
+               std::cerr << "creating game...\n";
+
+               //create the new game, remove the player from the
+               //lobby and put him/her in the game they have created
+               games_.push_back(game(players_));
+               lobby_players_.remove_player(sock);
+               games_.back().add_player(sock);
+
+               //store the game data here at the moment
+               games_.back().level() = *create_game;
+               std::stringstream converter;
+               converter << games_.back().id();
+               games_.back().level()["id"] = converter.str();
+
+               //mark the player as unavailable in the lobby
+               const player_map::iterator pl = players_.find(sock);
+               if(pl != players_.end()) {
+                       pl->second.mark_available(false);
+
+                       lobby_players_.send_data(sync_initial_response());
+               } else {
+                       std::cerr << "ERROR: Could not find player in map\n";
+               }
+
+               return;
+       }
+
+       //see if the player is joining a game
+       const config* const join = data.child("join");
+       if(join != NULL) {
+               const std::string& id = (*join)["id"];
+               const int nid = atoi(id.c_str());
+               const std::vector<game>::iterator it =
+                            std::find_if(games_.begin(),games_.end(),
+                                         game_id_matches(nid));
+               if(it == games_.end()) {
+                       //send a response saying the game has been cancelled
+                       config cfg;
+                       cfg.add_child("leave_game");
+                       network::send_data(cfg,sock);
+
+                       std::cerr << "attempt to join unknown game\n";
+                       return;
+               }
+
+               if(it->player_is_banned(sock)) {
+                       network::send_data(construct_error("You are banned from 
this game"),sock);
+                       return;
+               }
+
+               lobby_players_.remove_player(sock);
+
+               //send them the game data
+               network::send_data(it->level(),sock);
+
+               it->add_player(sock);
+
+               //mark the player as unavailable in the lobby
+               const player_map::iterator pl = players_.find(sock);
+               if(pl != players_.end()) {
+                       pl->second.mark_available(false);
+
+                       lobby_players_.send_data(sync_initial_response());
+               } else {
+                       std::cerr << "ERROR: Could not find player in map\n";
+               }
+       }
+
+       //see if it's a message, in which case we add the name
+       //of the sender, and forward it to all players in the lobby
+       config* const message = data.child("message");
+       if(message != NULL) {
+               const player_map::const_iterator p = players_.find(sock);
+               wassert(p != players_.end());
+               (*message)["sender"] = p->second.name();
+
+               truncate_message((*message)["message"]);
+
+               lobby_players_.send_data(data,sock);
+       }
+}
+
+void server::process_data_from_player_in_game(const network::connection sock, 
config& data, config& gamelist)
+{
+       std::vector<game>::iterator g;
+       for(g = games_.begin(); g != games_.end(); ++g) {
+               if(g->is_member(sock))
+                       break;
+       }
+
+       if(g == games_.end()) {
+               std::cerr << "ERROR: unknown socket " << games_.size() << "\n";
+               return;
+       }
+
+       //if info is being provided about the game state
+       if(data.child("info") != NULL) {
+               const config& info = *data.child("info");
+               if(info["type"] == "termination") {
+                       g->set_termination_reason(info["condition"]);
+               }
+       }
+
+       //if the owner is changing the controller for a side
+       if(g->is_owner(sock) && data.child("change_controller") != NULL) {
+               const config& change = *data.child("change_controller");
+               const std::string& result = g->transfer_side_control(change);
+               if(result == "") {
+                       const config& msg = 
construct_server_message(change["player"] + " takes control of side " + 
change["side"],*g);
+                       g->send_data(msg);
+               } else {
+                       const config& msg = construct_server_message(result,*g);
+                       network::send_data(msg,sock);
+               }
+
+               return;
+       }
+
+       //if the owner is banning someone from the game
+       if(g->is_owner(sock) && (data.child("ban") != NULL || 
data.child("kick") != NULL)) {
+               std::string name;
+               bool ban;
+               if (data.child("ban") != NULL) {
+                       const config& u = *data.child("ban");
+                       name = u["username"];
+                       ban = true;
+               } else if (data.child("kick") != NULL) {
+                       const config& u = *data.child("kick");
+                       name = u["username"];
+                       ban = false;
+               }
+       
+               player_map::iterator pl;
+               for(pl = players_.begin(); pl != players_.end(); ++pl) {
+                       if(pl->second.name() == name) {
+                               break;
+                       }
+               }
+
+               if(pl->first != sock && pl != players_.end()) {
+                       if (ban) {
+                               g->ban_player(pl->first);
+                               const config& msg = 
construct_server_message("You have been banned",*g);
+                               network::send_data(msg, pl->first);
+                       } else {
+                               g->remove_player(pl->first, false);
+                       }
+
+                       config leave_game;
+                       leave_game.add_child("leave_game");
+                       network::send_data(leave_game,pl->first);
+
+                       g->describe_slots();
+                       lobby_players_.add_player(pl->first);
+
+                       //mark the player as available in the lobby
+                       pl->second.mark_available(true);
+
+                       //send the player who was banned the lobby game list
+                       network::send_data(initial_response_,pl->first);
+
+                       //send all other players in the lobby the update to the 
lobby
+                       lobby_players_.send_data(sync_initial_response(),sock);
+               } else if(pl == players_.end()) {
+                       const config& response = construct_server_message(
+                                    "Ban failed: user '" + name + "' not 
found",*g);
+                       network::send_data(response,sock);
+               }
+       } else if(data.child("ban")) {
+               const config& response = construct_server_message(
+                            "You cannot ban: not the game creator",*g);
+               network::send_data(response,sock);
+       }
+
+       //if this is data describing changes to a game.
+       else if(g->is_owner(sock) && data.child("scenario_diff")) {
+               g->level().apply_diff(*data.child("scenario_diff"));
+               g->update_side_data();
+               g->send_data(data,sock);
+
+               const bool lobby_changes = g->describe_slots();
+               if(lobby_changes) {
+                       lobby_players_.send_data(sync_initial_response());
+               }
+       }
+
+       //if this is data describing the level for a game.
+       else if(g->is_owner(sock) && data.child("side") != NULL) {
+
+               const bool is_init = g->level_init();
+
+               //if this game is having its level data initialized
+               //for the first time, and is ready for players to join.
+               //We should currently have a summary of the game in g->level().
+               //we want to move this summary to the initial_response_, and
+               //place a pointer to that summary in the game's description.
+               //g->level() should then receive the full data for the game.
+               if(!is_init) {
+
+                       //if there is no shroud, then tell players in the lobby 
what the map looks like
+                       if((*data.child("side"))["shroud"] != "yes") {
+                               g->level().values["map_data"] = 
data["map_data"];
+                               g->level().values["map"] = data["map"];
+                       }
+                       
+                       //update our config object which describes the
+                       //open games, and notifies the game of where its 
description
+                       //is located at
+                       config& desc = gamelist.add_child("game",g->level());
+                       g->set_description(&desc);
+
+                       //record the full description of the scenario in 
g->level()
+                       g->level() = data;
+                       g->update_side_data();
+                       g->describe_slots();
+
+                       //send all players in the lobby the update to the list 
of games
+                       lobby_players_.send_data(sync_initial_response());
+               } else {
+
+                       //we've already initialized this scenario, but clobber 
its old
+                       //contents with the new ones given here
+                       g->level() = data;
+                       g->update_side_data();
+               }
+
+               //send all players in the level, except the sender, the new data
+               g->send_data(data,sock);
+               return;
+       }
+
+       const string_map::const_iterator side = data.values.find("side");
+       if(side != data.values.end()) {
+               const bool res = g->take_side(sock,data);
+               config response;
+               if(res) {
+                       std::cerr << "played joined side\n";
+                       response["side_secured"] = side->second;
+
+                       //update the number of available slots
+                       const bool res = g->describe_slots();
+                       if(res) {
+                               
lobby_players_.send_data(sync_initial_response());
+                       }
+               } else {
+                       response["failed"] = "yes";
+               }
+
+               network::send_data(response,sock);
+               return;
+       }
+
+       if(data.child("start_game")) {
+               //send notification of the game starting immediately.
+               //g->start_game() will send data that assumes the [start_game]
+               //message has been sent
+               g->send_data(data,sock);
+
+               g->start_game();
+               lobby_players_.send_data(sync_initial_response());
+               return;
+       } else if(data.child("leave_game")) {
+               const bool needed = g->is_needed(sock);
+
+               if(needed) {
+
+                       //tell all other players the game is over,
+                       //because a needed player has left
+                       config cfg;
+                       cfg.add_child("leave_game");
+                       g->send_data(cfg);
+
+                       //delete the game's description
+                       config* const gamelist = 
initial_response_.child("gamelist");
+                       wassert(gamelist != NULL);
+                       const config::child_itors vg = 
gamelist->child_range("game");
+
+                       const config::child_iterator desc = 
std::find(vg.first,vg.second,g->description());
+                       if(desc != vg.second) {
+                               gamelist->remove_child("game",desc - vg.first);
+                       }
+
+                       //update the state of the lobby to players in it.
+                       //We have to sync the state of the lobby so we can
+                       //send it to the players leaving the game
+                       lobby_players_.send_data(sync_initial_response());
+
+                       //set the availability status for all quitting players
+                       for(player_map::iterator pl = players_.begin(); pl != 
players_.end(); ++pl) {
+                               if(g->is_member(pl->first)) {
+                                       pl->second.mark_available(true);
+                               }
+                       }
+
+                       //put the players back in the lobby and send
+                       //them the game list and user list again
+                       g->send_data(initial_response_);
+                       metrics_.game_terminated(g->termination_reason());
+                       lobby_players_.add_players(*g);
+                       games_.erase(g);
+
+                       //now sync players in the lobby again, to remove the 
game
+                       lobby_players_.send_data(sync_initial_response());
+               } else {
+
+                       g->remove_player(sock);
+                       g->describe_slots();
+                       lobby_players_.add_player(sock);
+
+                       //mark the player as available in the lobby
+                       const player_map::iterator pl = players_.find(sock);
+                       if(pl != players_.end()) {
+                               pl->second.mark_available(true);
+                       } else {
+                               std::cerr << "ERROR: Could not find player in 
map\n";
+                       }
+
+                       //send the player who has quit the game list
+                       network::send_data(initial_response_,sock);
+
+                       //send all other players in the lobby the update to the 
lobby
+                       lobby_players_.send_data(sync_initial_response(),sock);
+               }
+
+               return;
+       } else if(data["side_secured"].empty() == false) {
+               return;
+       } else if(data["failed"].empty() == false) {
+               std::cerr << "ERROR: failure to get side\n";
+               return;
+       }
+
+       config* const turn = data.child("turn");
+       if(turn != NULL) {
+               g->filter_commands(sock,*turn);
+
+               //notify the game of the commands, and if it changes
+               //the description, then sync the new description
+               //to players in the lobby
+               const bool res = g->process_commands(*turn);
+               if(res) {
+                       lobby_players_.send_data(sync_initial_response());
+               }
+
+               //any private 'speak' commands must be repackaged seperate
+               //to other commands, and re-sent, since they should only go
+               //to some clients.
+               const config::child_itors speaks = turn->child_range("command");
+               int npublic = 0, nprivate = 0, nother = 0;
+               std::string team_name;
+               for(config::child_iterator i = speaks.first; i != 
speaks.second; ++i) {
+                       config* const speak = (*i)->child("speak");
+                       if(speak == NULL) {
+                               ++nother;
+                               continue;
+                       }
+
+                       truncate_message((*speak)["message"]);
+
+                       //force the description to be correct to prevent
+                       //spoofing of messages
+                       const player_map::const_iterator pl = 
players_.find(sock);
+                       wassert(pl != players_.end());
+                       (*speak)["description"] = pl->second.name();
+
+                       if((*speak)["team_name"] == "") {
+                               ++npublic;
+                       } else {
+                               ++nprivate;
+                               team_name = (*speak)["team_name"];
+                       }
+               }
+
+               //if all there are are messages and they're all private, then
+               //just forward them on to the client that should receive them.
+               if(nprivate > 0 && npublic == 0 && nother == 0) {
+                       g->send_data_team(data,team_name,sock);
+                       return;
+               }
+
+               //at the moment, if private messages are mixed in with other
+               //data, then let them go through. It's exceedingly unlikely that
+               //this will happen anyway, and if it does, the client should
+               //respect not displaying the message.
+       }
+
+       //forward data to all players who are in the game,
+       //except for the original data sender
+       g->send_data(data,sock);
+
+       if(g->started()) {
+               g->record_data(data);
+       }
+}
 
 void server::delete_game(std::vector<game>::iterator i)
 {
@@ -863,7 +885,10 @@
                } else if(val == "--help" || val == "-h") {
                        std::cout << "usage: " << argv[0]
                                << " [options]\n"
-                               << "  -p, --port     Binds the server to the 
specified port\n";
+                               << "      --fifo file            Sets the path 
for the FIFO used to communicate with the server\n"
+                               << "  -m, --max_packet_size n    Sets the 
maximal packet size to n\n" 
+                               << "  -p, --port                 Binds the 
server to the specified port\n"
+                               << "  -v, --version              Returns the 
server version\n";
                        return 0;
                } else if(val == "--version" || val == "-v") {
                        std::cout << "Battle for Wesnoth server " << 
game_config::version
Index: wesnoth/src/widgets/combo.cpp
diff -u wesnoth/src/widgets/combo.cpp:1.27 wesnoth/src/widgets/combo.cpp:1.28
--- wesnoth/src/widgets/combo.cpp:1.27  Wed Jan 12 21:33:58 2005
+++ wesnoth/src/widgets/combo.cpp       Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: combo.cpp,v 1.27 2005/01/12 21:33:58 silene Exp $ */
+/* $Id: combo.cpp,v 1.28 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -50,6 +50,11 @@
        selected_ = -1;
 }
 
+size_t combo::items_size() const
+{
+       return items_.size();
+}
+
 void combo::set_selected_internal(int val)
 {
        const size_t index = size_t(val);
Index: wesnoth/src/widgets/combo.hpp
diff -u wesnoth/src/widgets/combo.hpp:1.19 wesnoth/src/widgets/combo.hpp:1.20
--- wesnoth/src/widgets/combo.hpp:1.19  Wed Jan 12 21:33:58 2005
+++ wesnoth/src/widgets/combo.hpp       Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: combo.hpp,v 1.19 2005/01/12 21:33:58 silene Exp $ */
+/* $Id: combo.hpp,v 1.20 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -27,6 +27,7 @@
 
        void set_selected(int val);
        void set_items(const std::vector<std::string>& items);
+       size_t items_size() const;
        int selected() const;
        bool changed();
 
Index: wesnoth/src/widgets/scrollpane.cpp
diff -u wesnoth/src/widgets/scrollpane.cpp:1.6 
wesnoth/src/widgets/scrollpane.cpp:1.7
--- wesnoth/src/widgets/scrollpane.cpp:1.6      Mon Nov 22 23:54:27 2004
+++ wesnoth/src/widgets/scrollpane.cpp  Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: scrollpane.cpp,v 1.6 2004/11/22 23:54:27 ydirson Exp $ */
+/* $Id: scrollpane.cpp,v 1.7 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2004 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -46,10 +46,23 @@
 void scrollpane::clear()
 {
        content_.clear();
-       
        update_content_size();
 }
 
+void scrollpane::set_location(SDL_Rect const& rect)
+{
+       scrollarea::set_location(rect);
+       set_shown_size(client_area().h);
+       update_widget_positions();
+}
+
+void scrollpane::hide(bool value)
+{
+       for(widget_map::iterator itor = content_.begin(); itor != 
content_.end(); ++itor) {
+               itor->second.w->hide(value);
+       }
+}
+
 void scrollpane::add_widget(widget* w, int x, int y, int z_order)
 {
        if (w == NULL)
@@ -98,10 +111,14 @@
                return;
 
        content_pos_.y = pos;
-       widget_map::iterator itor; 
+       update_widget_positions();
+}
 
-       std::vector<bool> hidden(content_.size());
+void scrollpane::update_widget_positions()
+{
 
+       widget_map::iterator itor; 
+       std::vector<bool> hidden(content_.size());
        int i = 0;
        for(itor = content_.begin(); itor != content_.end(); ++itor) {
                hidden[i++] = itor->second.w->hidden();
Index: wesnoth/src/widgets/scrollpane.hpp
diff -u wesnoth/src/widgets/scrollpane.hpp:1.3 
wesnoth/src/widgets/scrollpane.hpp:1.4
--- wesnoth/src/widgets/scrollpane.hpp:1.3      Thu Nov 18 04:08:33 2004
+++ wesnoth/src/widgets/scrollpane.hpp  Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: scrollpane.hpp,v 1.3 2004/11/18 04:08:33 Sirp Exp $ */
+/* $Id: scrollpane.hpp,v 1.4 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2004 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -43,6 +43,11 @@
        /// \param callback a callback interface for warning that the grip has 
been moved
        scrollpane(display &d);
 
+       virtual void set_location(SDL_Rect const &rect);
+       using widget::set_location;
+
+       virtual void hide(bool value=true);
+
        void add_widget(widget* w, int x, int y, int z_order = 0);
        void remove_widget(widget* w);
        void clear();
@@ -55,6 +60,7 @@
        virtual void scroll(int pos);
 
 private:
+       void update_widget_positions();
        void position_widget(scrollpane_widget& spw);
        SDL_Rect client_area() const;
        void update_content_size();
Index: wesnoth/src/widgets/textbox.cpp
diff -u wesnoth/src/widgets/textbox.cpp:1.68 
wesnoth/src/widgets/textbox.cpp:1.69
--- wesnoth/src/widgets/textbox.cpp:1.68        Sun Jan 23 00:28:34 2005
+++ wesnoth/src/widgets/textbox.cpp     Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: textbox.cpp,v 1.68 2005/01/23 00:28:34 Sirp Exp $ */
+/* $Id: textbox.cpp,v 1.69 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -214,6 +214,13 @@
        }
 }
 
+void textbox::set_location(const SDL_Rect& rect)
+{
+       text_pos_ = 0;
+
+       scrollarea::set_location(rect);
+}
+
 void textbox::scroll(int pos)
 {
        yscroll_ = pos;
Index: wesnoth/src/widgets/textbox.hpp
diff -u wesnoth/src/widgets/textbox.hpp:1.36 
wesnoth/src/widgets/textbox.hpp:1.37
--- wesnoth/src/widgets/textbox.hpp:1.36        Sat Nov 13 00:27:26 2004
+++ wesnoth/src/widgets/textbox.hpp     Sun Feb 20 22:30:29 2005
@@ -1,4 +1,4 @@
-/* $Id: textbox.hpp,v 1.36 2004/11/13 00:27:26 isaaccp Exp $ */
+/* $Id: textbox.hpp,v 1.37 2005/02/20 22:30:29 gruikya Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -43,6 +43,9 @@
 
        void set_wrap(bool val);
 
+       void set_location(const SDL_Rect& rect);
+       using scrollarea::set_location;
+
 protected:
        virtual void draw_contents();
        virtual void set_inner_location(SDL_Rect const &);




reply via email to

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