multiplayer.cpp

Go to the documentation of this file.
00001 /* $Id: multiplayer.cpp 53604 2012-03-21 20:42:13Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2007 - 2012
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include "dialogs.hpp"
00019 #include "gettext.hpp"
00020 #include "game_preferences.hpp"
00021 #include "log.hpp"
00022 #include "gui/dialogs/lobby_main.hpp"
00023 #include "gui/dialogs/message.hpp"
00024 #include "gui/dialogs/mp_connect.hpp"
00025 #include "gui/dialogs/mp_create_game.hpp"
00026 #include "gui/dialogs/mp_login.hpp"
00027 #include "gui/widgets/settings.hpp"
00028 #include "gui/widgets/window.hpp"
00029 #include "hash.hpp"
00030 #include "multiplayer.hpp"
00031 #include "multiplayer_connect.hpp"
00032 #include "multiplayer_create.hpp"
00033 #include "multiplayer_error_codes.hpp"
00034 #include "multiplayer_wait.hpp"
00035 #include "multiplayer_lobby.hpp"
00036 #include "playmp_controller.hpp"
00037 #include "playcampaign.hpp"
00038 #include "formula_string_utils.hpp"
00039 #include "sound.hpp"
00040 #include "unit_id.hpp"
00041 
00042 #include <boost/bind.hpp>
00043 
00044 static lg::log_domain log_network("network");
00045 #define LOG_NW LOG_STREAM(info, log_network)
00046 
00047 static lg::log_domain log_mp("mp/main");
00048 #define DBG_MP LOG_STREAM(debug, log_mp)
00049 
00050 namespace {
00051 
00052 class network_game_manager
00053 {
00054 public:
00055     // Add a constructor to avoid stupid warnings with some versions of GCC
00056     network_game_manager() {};
00057 
00058     ~network_game_manager()
00059     {
00060         if(network::nconnections() > 0) {
00061             LOG_NW << "sending leave_game\n";
00062             config cfg;
00063             cfg.add_child("leave_game");
00064             network::send_data(cfg, 0);
00065             LOG_NW << "sent leave_game\n";
00066         }
00067     };
00068 };
00069 
00070 }
00071 
00072 static void run_lobby_loop(display& disp, mp::ui& ui)
00073 {
00074     DBG_MP << "running lobby loop" << std::endl;
00075     disp.video().modeChanged();
00076     bool first = true;
00077     font::cache_mode(font::CACHE_LOBBY);
00078     while (ui.get_result() == mp::ui::CONTINUE) {
00079         if (disp.video().modeChanged() || first) {
00080             SDL_Rect lobby_pos = create_rect(0
00081                     , 0
00082                     , disp.video().getx()
00083                     , disp.video().gety());
00084             ui.set_location(lobby_pos);
00085             first = false;
00086         }
00087         // process network data first so user actions can override the result
00088         // or uptodate data can prevent invalid actions
00089         // i.e. press cancel while you receive [start_game] or press start game while someone leaves
00090         ui.process_network();
00091 
00092         events::pump();
00093         events::raise_process_event();
00094         events::raise_draw_event();
00095 
00096         disp.flip();
00097         disp.delay(20);
00098     }
00099     font::cache_mode(font::CACHE_GAME);
00100 }
00101 
00102 namespace {
00103 
00104 enum server_type {
00105     ABORT_SERVER,
00106     WESNOTHD_SERVER,
00107     SIMPLE_SERVER
00108 };
00109 
00110 }
00111 
00112 static server_type open_connection(game_display& disp, const std::string& original_host)
00113 {
00114     DBG_MP << "opening connection" << std::endl;
00115     std::string h = original_host;
00116 
00117     if(h.empty()) {
00118         gui2::tmp_connect dlg;
00119 
00120         dlg.show(disp.video());
00121         if(dlg.get_retval() == gui2::twindow::OK) {
00122             h = preferences::network_host();
00123         } else {
00124             return ABORT_SERVER;
00125         }
00126     }
00127 
00128     network::connection sock;
00129 
00130     const int pos = h.find_first_of(":");
00131     std::string host;
00132     unsigned int port;
00133 
00134     if(pos == -1) {
00135         host = h;
00136         port = 15000;
00137     } else {
00138         host = h.substr(0, pos);
00139         port = lexical_cast_default<unsigned int>(h.substr(pos + 1), 15000);
00140     }
00141 
00142     // shown_hosts is used to prevent the client being locked in a redirect
00143     // loop.
00144     typedef std::pair<std::string, int> hostpair;
00145     std::set<hostpair> shown_hosts;
00146     shown_hosts.insert(hostpair(host, port));
00147 
00148     config data;
00149     sock = dialogs::network_connect_dialog(disp,_("Connecting to Server..."),host,port);
00150 
00151     do {
00152 
00153         if (!sock) {
00154             return ABORT_SERVER;
00155         }
00156 
00157         data.clear();
00158         network::connection data_res = dialogs::network_receive_dialog(
00159                 disp,_("Reading from Server..."),data);
00160         if (!data_res) return ABORT_SERVER;
00161         mp::check_response(data_res, data);
00162 
00163         // Backwards-compatibility "version" attribute
00164         const std::string& version = data["version"];
00165         if(version.empty() == false && version != game_config::version) {
00166             utils::string_map i18n_symbols;
00167             i18n_symbols["version1"] = version;
00168             i18n_symbols["version2"] = game_config::version;
00169             const std::string errorstring = vgettext("The server requires version '$version1' while you are using version '$version2'", i18n_symbols);
00170             throw network::error(errorstring);
00171         }
00172 
00173         // Check for "redirect" messages
00174         if (const config &redirect = data.child("redirect"))
00175         {
00176             host = redirect["host"].str();
00177             port =redirect["port"].to_int(15000);
00178 
00179             if(shown_hosts.find(hostpair(host,port)) != shown_hosts.end()) {
00180                 throw network::error(_("Server-side redirect loop"));
00181             }
00182             shown_hosts.insert(hostpair(host, port));
00183 
00184             if(network::nconnections() > 0)
00185                 network::disconnect();
00186             sock = dialogs::network_connect_dialog(disp,_("Connecting to Server..."),host,port);
00187             continue;
00188         }
00189 
00190         if(data.child("version")) {
00191             config cfg;
00192             config res;
00193             cfg["version"] = game_config::version;
00194             res.add_child("version", cfg);
00195             network::send_data(res, 0);
00196         }
00197 
00198         //if we got a direction to login
00199         if(data.child("mustlogin")) {
00200 
00201             for(;;) {
00202                 std::string password_reminder = "";
00203 
00204                 std::string login = preferences::login();
00205 
00206                 config response ;
00207                 config &sp = response.add_child("login") ;
00208                 sp["username"] = login ;
00209 
00210                 // Login and enable selective pings -- saves server bandwidth
00211                 // If ping_timeout has a non-zero value, do not enable
00212                 // selective pings as this will cause clients to falsely
00213                 // believe the server has died and disconnect.
00214                 if (preferences::get_ping_timeout()) {
00215                     // Pings required so disable selective pings
00216                     sp["selective_ping"] = false;
00217                 } else {
00218                     // Client is bandwidth friendly so allow
00219                     // server to optimize ping frequency as needed.
00220                     sp["selective_ping"] = true;
00221                 }
00222                 network::send_data(response, 0);
00223 
00224                 // Get response for our login request...
00225                 network::connection data_res = network::receive_data(data, 0, 3000);
00226                 if(!data_res) {
00227                     throw network::error(_("Connection timed out"));
00228                 }
00229 
00230                 config *warning = &data.child("warning");
00231 
00232                 if(*warning) {
00233                     std::string warning_msg;
00234 
00235                     utils::string_map i18n_symbols;
00236                     i18n_symbols["nick"] = login;
00237 
00238                     if((*warning)["warning_code"] == MP_NAME_INACTIVE_WARNING) {
00239                         warning_msg = vgettext("The nickname ‘$nick’ is inactive. "
00240                             "You cannot claim ownership of this nickname until you "
00241                             "activate your account via email or ask an "
00242                             "administrator to do it for you.", i18n_symbols);
00243                     } else {
00244                         warning_msg = (*warning)["message"].str();
00245                     }
00246 
00247                     warning_msg += "\n\n";
00248                     warning_msg += _("Do you want to continue?");
00249 
00250                     if(gui2::show_message(disp.video(), _("Warning"), warning_msg, gui2::tmessage::yes_no_buttons) != gui2::twindow::OK) {
00251                         return ABORT_SERVER;
00252                     }
00253                 }
00254 
00255                 config *error = &data.child("error");
00256 
00257                 // ... and get us out of here if the server did not complain
00258                 if (!*error) break;
00259 
00260                 do {
00261                     std::string password = preferences::password();
00262 
00263                     bool fall_through = (*error)["force_confirmation"].to_bool() ?
00264                         (gui2::show_message(disp.video(), _("Confirm"), (*error)["message"], gui2::tmessage::ok_cancel_buttons) == gui2::twindow::CANCEL) :
00265                         false;
00266 
00267                     const bool is_pw_request = !((*error)["password_request"].empty()) && !(password.empty());
00268 
00269                     // If the server asks for a password, provide one if we can
00270                     // or request a password reminder.
00271                     // Otherwise or if the user pressed 'cancel' in the confirmation dialog
00272                     // above go directly to the username/password dialog
00273                     if((is_pw_request || !password_reminder.empty()) && !fall_through) {
00274                         if(is_pw_request) {
00275                             if ((*error)["phpbb_encryption"].to_bool())
00276                             {
00277 
00278                                 // Apparently HTML key-characters are passed to the hashing functions of phpbb in this escaped form.
00279                                 // I will do closer investigations on this, for now let's just hope these are all of them.
00280 
00281                                 // Note: we must obviously replace '&' first, I wasted some time before I figured that out... :)
00282                                 for(std::string::size_type pos = 0; (pos = password.find('&', pos)) != std::string::npos; ++pos )
00283                                     password.replace(pos, 1, "&amp;");
00284                                 for(std::string::size_type pos = 0; (pos = password.find('\"', pos)) != std::string::npos; ++pos )
00285                                     password.replace(pos, 1, "&quot;");
00286                                 for(std::string::size_type pos = 0; (pos = password.find('<', pos)) != std::string::npos; ++pos )
00287                                     password.replace(pos, 1, "&lt;");
00288                                 for(std::string::size_type pos = 0; (pos = password.find('>', pos)) != std::string::npos; ++pos )
00289                                     password.replace(pos, 1, "&gt;");
00290 
00291                                 const std::string salt = (*error)["salt"];
00292 
00293                                 if (salt.length() < 12) {
00294                                     throw network::error(_("Bad data received from server"));
00295                                 }
00296 
00297                                 sp["password"] = util::create_hash(util::create_hash(password, util::get_salt(salt),
00298                                         util::get_iteration_count(salt)), salt.substr(12, 8));
00299 
00300                             } else {
00301                                 sp["password"] = password;
00302                             }
00303                         }
00304 
00305                         sp["password_reminder"] = password_reminder;
00306 
00307                         // Once again send our request...
00308                         network::send_data(response, 0);
00309 
00310                         network::connection data_res = network::receive_data(data, 0, 3000);
00311                         if(!data_res) {
00312                             throw network::error(_("Connection timed out"));
00313                         }
00314 
00315                         error = &data.child("error");
00316 
00317                         // ... and get us out of here if the server is happy now
00318                         if (!*error) break;
00319 
00320 
00321                     }
00322 
00323                     password_reminder = "";
00324 
00325                     // Providing a password either was not attempted because we did not
00326                     // have any or failed:
00327                     // Now show a dialog that displays the error and allows to
00328                     // enter a new user name and/or password
00329 
00330                     std::string error_message;
00331                     utils::string_map i18n_symbols;
00332                     i18n_symbols["nick"] = login;
00333 
00334                     if((*error)["error_code"] == MP_MUST_LOGIN) {
00335                         error_message = _("You must login first.");
00336                     } else if((*error)["error_code"] == MP_NAME_TAKEN_ERROR) {
00337                         error_message = vgettext("The nickname ‘$nick’ is already taken.", i18n_symbols);
00338                     } else if((*error)["error_code"] == MP_INVALID_CHARS_IN_NAME_ERROR) {
00339                         error_message = vgettext("The nickname ‘$nick’ contains invalid "
00340                                 "characters. Only alpha-numeric characters, underscores and "
00341                                 "hyphens are allowed.", i18n_symbols);
00342                     } else if((*error)["error_code"] == MP_NAME_TOO_LONG_ERROR) {
00343                         error_message = vgettext("The nickname ‘$nick’ is too long. Nicks must "
00344                                 "be 20 characters or less.", i18n_symbols);
00345                     } else if((*error)["error_code"] == MP_NAME_RESERVED_ERROR) {
00346                         error_message = vgettext("The nickname ‘$nick’ is reserved and cannot be used by players.", i18n_symbols);
00347                     } else if((*error)["error_code"] == MP_NAME_UNREGISTERED_ERROR) {
00348                         error_message = vgettext("The nickname ‘$nick’ is not registered on this server.", i18n_symbols)
00349                                 + _(" This server disallows unregistered nicknames.");
00350                     } else if((*error)["error_code"] == MP_PASSWORD_REQUEST) {
00351                         error_message = vgettext("The nickname ‘$nick’ is registered on this server.", i18n_symbols);
00352                     } else if((*error)["error_code"] == MP_PASSWORD_REQUEST_FOR_LOGGED_IN_NAME) {
00353                         error_message = vgettext("The nickname ‘$nick’ is registered on this server.", i18n_symbols)
00354                                 + "\n\n" + _("WARNING: There is already a client using this nickname, "
00355                                 "logging in will cause that client to be kicked!");
00356                     } else if((*error)["error_code"] == MP_NO_SEED_ERROR) {
00357                         error_message = _("Error in the login procedure (the server had no "
00358                                 "seed for your connection).");
00359                     } else if((*error)["error_code"] == MP_INCORRECT_PASSWORD_ERROR) {
00360                         error_message = _("The password you provided was incorrect.");
00361                     } else if((*error)["error_code"] == MP_TOO_MANY_ATTEMPTS_ERROR) {
00362                         error_message = _("You have made too many login attempts.");
00363                     } else {
00364                         error_message = (*error)["message"].str();
00365                     }
00366 
00367                     gui2::tmp_login dlg(error_message, !((*error)["password_request"].empty()));
00368                     dlg.show(disp.video());
00369 
00370                     switch(dlg.get_retval()) {
00371                         //Log in with password
00372                         case gui2::twindow::OK:
00373                             break;
00374                         //Request a password reminder
00375                         case 1:
00376                             password_reminder = "yes";
00377                             break;
00378                         // Cancel
00379                         default: return ABORT_SERVER;
00380                     }
00381 
00382                 // If we have got a new username we have to start all over again
00383                 } while(login == preferences::login());
00384 
00385                 // Somewhat hacky...
00386                 // If we broke out of the do-while loop above error
00387                 // is still going to be NULL
00388                 if(!*error) break;
00389             } // end login loop
00390         }
00391     } while(!(data.child("join_lobby") || data.child("join_game")));
00392 
00393     if (h != preferences::server_list().front().address)
00394         preferences::set_network_host(h);
00395 
00396     if (data.child("join_lobby")) {
00397         return WESNOTHD_SERVER;
00398     } else {
00399         return SIMPLE_SERVER;
00400     }
00401 
00402 }
00403 
00404 
00405 // The multiplayer logic consists in 4 screens:
00406 //
00407 // lobby <-> create <-> connect <-> (game)
00408 //       <------------> wait    <-> (game)
00409 //
00410 // To each of this screen corresponds a dialog, each dialog being defined in
00411 // the multiplayer_(screen) file.
00412 //
00413 // The functions enter_(screen)_mode are simple functions that take care of
00414 // creating the dialogs, then, according to the dialog result, of calling other
00415 // of those screen functions.
00416 
00417 static void enter_wait_mode(game_display& disp, const config& game_config, mp::chat& chat, config& gamelist, bool observe)
00418 {
00419     DBG_MP << "entering wait mode" << std::endl;
00420 
00421     mp::ui::result res;
00422     game_state state;
00423     network_game_manager m;
00424 
00425     gamelist.clear();
00426     statistics::fresh_stats();
00427     n_unit::id_manager::instance().clear(); //< reset the unit underlying_id counter back to zero
00428 
00429     {
00430         mp::wait ui(disp, game_config, chat, gamelist);
00431 
00432         ui.join_game(observe);
00433 
00434         run_lobby_loop(disp, ui);
00435         res = ui.get_result();
00436 
00437         if (res == mp::ui::PLAY) {
00438             ui.start_game();
00439             // FIXME commented a pointeless if since the else does exactly the same thing
00440             //if (preferences::skip_mp_replay()){
00441                 //FIXME implement true skip replay
00442                 //state = ui.request_snapshot();
00443                 //state = ui.get_state();
00444             //}
00445             //else{
00446                 state = ui.get_state();
00447             //}
00448         }
00449     }
00450 
00451     switch (res) {
00452     case mp::ui::PLAY:
00453         play_game(disp, state, game_config, IO_CLIENT,
00454             preferences::skip_mp_replay() && observe);
00455         recorder.clear();
00456 
00457         break;
00458     case mp::ui::QUIT:
00459     default:
00460         break;
00461     }
00462 }
00463 
00464 static void enter_create_mode(game_display& disp, const config& game_config, mp::chat& chat, config& gamelist, mp::controller default_controller, bool local_players_only = false);
00465 
00466 static bool enter_connect_mode(game_display& disp, const config& game_config,
00467         mp::chat& chat, config& gamelist, const mp_game_settings& params,
00468         const int num_turns, mp::controller default_controller, bool local_players_only = false)
00469 {
00470     DBG_MP << "entering connect mode" << std::endl;
00471 
00472     mp::ui::result res;
00473     game_state state;
00474     const network::manager net_manager(1,1);
00475     network_game_manager m;
00476 
00477     gamelist.clear();
00478     statistics::fresh_stats();
00479 
00480     {
00481         mp::connect ui(disp, game_config, chat, gamelist, params, num_turns, default_controller, local_players_only);
00482         run_lobby_loop(disp, ui);
00483 
00484         res = ui.get_result();
00485 
00486         // start_game() updates the parameters to reflect game start,
00487         // so it must be called before get_level()
00488         if (res == mp::ui::PLAY) {
00489             ui.start_game();
00490             state = ui.get_state();
00491         }
00492     }
00493 
00494     switch (res) {
00495     case mp::ui::PLAY:
00496         play_game(disp, state, game_config, IO_SERVER);
00497         recorder.clear();
00498 
00499         break;
00500     case mp::ui::CREATE:
00501         enter_create_mode(disp, game_config, chat, gamelist, default_controller, local_players_only);
00502         break;
00503     case mp::ui::QUIT:
00504     default:
00505         network::send_data(config("refresh_lobby"), 0);
00506         return false;
00507     }
00508 
00509     return true;
00510 }
00511 
00512 static void enter_create_mode(game_display& disp, const config& game_config, mp::chat& chat, config& gamelist, mp::controller default_controller, bool local_players_only)
00513 {
00514     DBG_MP << "entering create mode" << std::endl;
00515 
00516     bool connect_canceled;
00517 
00518     do {
00519         connect_canceled = false;
00520 
00521         if (gui2::new_widgets) {
00522 
00523             gui2::tmp_create_game dlg(game_config);
00524 
00525             dlg.show(disp.video());
00526 
00527             network::send_data(config("refresh_lobby"), 0);
00528         } else {
00529 
00530             mp::ui::result res;
00531             mp_game_settings params;
00532             int num_turns;
00533 
00534             {
00535                 mp::create ui(disp, game_config, chat, gamelist, local_players_only);
00536                 run_lobby_loop(disp, ui);
00537                 res = ui.get_result();
00538                 params = ui.get_parameters();
00539                 num_turns = ui.num_turns();
00540             }
00541 
00542             switch (res) {
00543             case mp::ui::CREATE:
00544                 connect_canceled = !enter_connect_mode(disp, game_config, chat, gamelist, params, num_turns, default_controller, local_players_only);
00545                 break;
00546             case mp::ui::QUIT:
00547             default:
00548                 //update lobby content
00549                 network::send_data(config("refresh_lobby"), 0);
00550                 break;
00551             }
00552         }
00553     } while(connect_canceled);
00554 }
00555 
00556 static void do_preferences_dialog(game_display& disp, const config& game_config)
00557 {
00558     DBG_MP << "displaying preferences dialog" << std::endl;
00559     const preferences::display_manager disp_manager(&disp);
00560     preferences::show_preferences_dialog(disp,game_config);
00561 
00562     /**
00563      * The screen size might have changed force an update of the size.
00564      *
00565      * @todo This might no longer be needed when gui2 is done.
00566      */
00567     const SDL_Rect rect = screen_area();
00568     preferences::set_resolution(disp.video(), rect.w, rect.h);
00569 
00570     gui2::settings::gamemap_width += rect.w - gui2::settings::screen_width ;
00571     gui2::settings::gamemap_height += rect.h - gui2::settings::screen_height ;
00572     gui2::settings::screen_width = rect.w;
00573     gui2::settings::screen_height = rect.h;
00574 }
00575 
00576 static void enter_lobby_mode(game_display& disp, const config& game_config, mp::chat& chat, config& gamelist)
00577 {
00578     DBG_MP << "entering lobby mode" << std::endl;
00579 
00580     mp::ui::result res;
00581 
00582     while (true) {
00583         const config &cfg = game_config.child("lobby_music");
00584         if (cfg) {
00585             foreach (const config &i, cfg.child_range("music")) {
00586                 sound::play_music_config(i);
00587             }
00588             sound::commit_music_changes();
00589         } else {
00590             sound::empty_playlist();
00591             sound::stop_music();
00592         }
00593         lobby_info li(game_config);
00594 
00595         // Force a black background
00596         const Uint32 color = SDL_MapRGBA(disp.video().getSurface()->format
00597                 , 0
00598                 , 0
00599                 , 0
00600                 , 255);
00601 
00602         sdl_fill_rect(disp.video().getSurface(), NULL, color);
00603 
00604         if(preferences::new_lobby()) {
00605             gui2::tlobby_main dlg(game_config, li, disp);
00606             dlg.set_preferences_callback(
00607                 boost::bind(do_preferences_dialog,
00608                     boost::ref(disp), boost::ref(game_config)));
00609             dlg.show(disp.video());
00610             //ugly kludge for launching other dialogs like the old lobby
00611             switch (dlg.get_legacy_result()) {
00612                 case gui2::tlobby_main::CREATE:
00613                     res = mp::ui::CREATE;
00614                     break;
00615                 case gui2::tlobby_main::JOIN:
00616                     res = mp::ui::JOIN;
00617                     break;
00618                 case gui2::tlobby_main::OBSERVE:
00619                     res = mp::ui::OBSERVE;
00620                     break;
00621                 default:
00622                     res = mp::ui::QUIT;
00623             }
00624         } else {
00625             mp::lobby ui(disp, game_config, chat, gamelist);
00626             run_lobby_loop(disp, ui);
00627             res = ui.get_result();
00628         }
00629 
00630         switch (res) {
00631         case mp::ui::JOIN:
00632             try {
00633                 enter_wait_mode(disp, game_config, chat, gamelist, false);
00634             } catch(config::error& error) {
00635                 if(!error.message.empty()) {
00636                     gui2::show_error_message(disp.video(), error.message);
00637                 }
00638                 //update lobby content
00639                 network::send_data(config("refresh_lobby"), 0);
00640             }
00641             break;
00642         case mp::ui::OBSERVE:
00643             try {
00644                 enter_wait_mode(disp, game_config, chat, gamelist, true);
00645             } catch(config::error& error) {
00646                 if(!error.message.empty()) {
00647                     gui2::show_error_message(disp.video(), error.message);
00648                 }
00649             }
00650             // update lobby content unconditionally because we might have left only after the
00651             // game ended in which case we ignored the gamelist and need to request it again
00652             network::send_data(config("refresh_lobby"), 0);
00653             break;
00654         case mp::ui::CREATE:
00655             try {
00656                 enter_create_mode(disp, game_config, chat, gamelist, mp::CNTR_NETWORK);
00657             } catch(config::error& error) {
00658                 if (!error.message.empty())
00659                     gui2::show_error_message(disp.video(), error.message);
00660                 //update lobby content
00661                 network::send_data(config("refresh_lobby"), 0);
00662             }
00663             break;
00664         case mp::ui::QUIT:
00665             return;
00666         case mp::ui::PREFERENCES:
00667             {
00668                 do_preferences_dialog(disp, game_config);
00669                 //update lobby content
00670                 network::send_data(config("refresh_lobby"), 0);
00671             }
00672             break;
00673         default:
00674             return;
00675         }
00676     }
00677 }
00678 
00679 namespace mp {
00680 
00681 void start_local_game(game_display& disp, const config& game_config,
00682         mp::controller default_controller)
00683 {
00684     DBG_MP << "starting local game" << std::endl;
00685     const rand_rng::set_random_generator generator_setter(&recorder);
00686     mp::chat chat;
00687     config gamelist;
00688     playmp_controller::set_replay_last_turn(0);
00689     preferences::set_message_private(false);
00690     enter_create_mode(disp, game_config, chat, gamelist, default_controller, true);
00691 }
00692 
00693 void start_client(game_display& disp, const config& game_config,
00694         const std::string& host)
00695 {
00696     DBG_MP << "starting client" << std::endl;
00697     const rand_rng::set_random_generator generator_setter(&recorder);
00698     const network::manager net_manager(1,1);
00699 
00700     mp::chat chat;
00701     config gamelist;
00702     server_type type = open_connection(disp, host);
00703 
00704     switch(type) {
00705     case WESNOTHD_SERVER:
00706         enter_lobby_mode(disp, game_config, chat, gamelist);
00707         break;
00708     case SIMPLE_SERVER:
00709         playmp_controller::set_replay_last_turn(0);
00710         preferences::set_message_private(false);
00711         enter_wait_mode(disp, game_config, chat, gamelist, false);
00712         break;
00713     case ABORT_SERVER:
00714         break;
00715     }
00716 }
00717 
00718 }
00719 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:06 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs