00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #include "construct_dialog.hpp"
00018 #include "dialogs.hpp"
00019 #include "game_display.hpp"
00020 #include "game_events.hpp"
00021 #include "game_preferences.hpp"
00022 #include "gettext.hpp"
00023 #include "leader_list.hpp"
00024 #include "log.hpp"
00025 #include "marked-up_text.hpp"
00026 #include "multiplayer.hpp"
00027 #include "multiplayer_wait.hpp"
00028 #include "replay.hpp"
00029 #include "statistics.hpp"
00030 #include "util.hpp"
00031 #include "video.hpp"
00032 #include "wml_separators.hpp"
00033 #include "serialization/string_utils.hpp"
00034
00035 #include <cassert>
00036
00037 #define DBG_NW LOG_STREAM(debug, network)
00038 #define LOG_NW LOG_STREAM(info, network)
00039 #define ERR_NW LOG_STREAM(err, network)
00040
00041 namespace {
00042 const SDL_Rect leader_pane_position = {-260,-370,260,370};
00043 const int leader_pane_border = 10;
00044 }
00045
00046 namespace mp {
00047
00048 wait::leader_preview_pane::leader_preview_pane(game_display& disp,
00049 const config::child_list& side_list) :
00050 gui::preview_pane(disp.video()),
00051 side_list_(side_list),
00052 leader_combo_(disp, std::vector<std::string>()),
00053 gender_combo_(disp, std::vector<std::string>()),
00054 leaders_(side_list, &leader_combo_, &gender_combo_),
00055 selection_(0)
00056 {
00057 set_location(leader_pane_position);
00058 }
00059
00060 void wait::leader_preview_pane::process_event()
00061 {
00062
00063 if (leader_combo_.changed() || gender_combo_.changed()) {
00064 leaders_.set_leader_combo(&leader_combo_);
00065 leaders_.update_gender_list(leaders_.get_leader());
00066 set_dirty();
00067 }
00068 }
00069
00070 void wait::leader_preview_pane::draw_contents()
00071 {
00072 bg_restore();
00073
00074 surface const screen = video().getSurface();
00075
00076 SDL_Rect const &loc = location();
00077 const SDL_Rect area = { loc.x + leader_pane_border, loc.y + leader_pane_border,
00078 loc.w - leader_pane_border * 2, loc.h - leader_pane_border * 2 };
00079 SDL_Rect clip_area = area;
00080 const clip_rect_setter clipper(screen,clip_area);
00081
00082 if(selection_ < side_list_.size()) {
00083 const config& side = *side_list_[selection_];
00084 std::string faction = side["faction"];
00085
00086 const std::string recruits = side["recruit"];
00087 const std::vector<std::string> recruit_list = utils::split(recruits);
00088 std::ostringstream recruit_string;
00089
00090 if(faction[0] == font::IMAGE) {
00091 std::string::size_type p = faction.find_first_of(COLUMN_SEPARATOR);
00092 if(p != std::string::npos && p < faction.size())
00093 faction = faction.substr(p+1);
00094 }
00095 std::string leader = leaders_.get_leader();
00096 std::string gender = leaders_.get_gender();
00097
00098 unit_type_data::unit_type_map_wrapper& utypes = unit_type_data::types();
00099 std::string leader_name;
00100 std::string image;
00101
00102 const unit_type* ut;
00103 const unit_type* utg;
00104
00105 if (utypes.find(leader) != utypes.end() && leader != "random") {
00106 ut = &(utypes.find(leader)->second);
00107 if (!gender.empty()) {
00108 if (gender == "female")
00109 utg = &(ut->get_gender_unit_type(unit_race::FEMALE));
00110 else
00111 utg = &(ut->get_gender_unit_type(unit_race::MALE));
00112 } else
00113 utg = ut;
00114
00115 leader_name = utg->type_name();
00116 #ifdef LOW_MEM
00117 image = utg->image();
00118 #else
00119 image = utg->image() + std::string("~RC(") + std::string(utg->flag_rgb() + ">1)");
00120 #endif
00121 }
00122
00123 for(std::vector<std::string>::const_iterator itor = recruit_list.begin();
00124 itor != recruit_list.end(); ++itor) {
00125
00126 if (utypes.find(*itor) != utypes.end()) {
00127 if(itor != recruit_list.begin())
00128 recruit_string << ", ";
00129 recruit_string << utypes.find(*itor)->second.type_name();
00130 }
00131 }
00132
00133 SDL_Rect image_rect = {area.x,area.y,0,0};
00134
00135 surface unit_image(image::get_image(image));
00136
00137 if(!unit_image.null()) {
00138 image_rect.w = unit_image->w;
00139 image_rect.h = unit_image->h;
00140 SDL_BlitSurface(unit_image,NULL,screen,&image_rect);
00141 }
00142
00143 font::draw_text(&video(),area,font::SIZE_PLUS,font::NORMAL_COLOUR,faction,area.x + 110, area.y + 60);
00144 const SDL_Rect leader_rect = font::draw_text(&video(),area,font::SIZE_SMALL,font::NORMAL_COLOUR,
00145 _("Leader: "),area.x, area.y + 110);
00146 const SDL_Rect gender_rect = font::draw_text(&video(),area,font::SIZE_SMALL,font::NORMAL_COLOUR,
00147 _("Gender: "),area.x, leader_rect.y + 30 + (leader_rect.h - leader_combo_.height()) / 2);
00148 font::draw_wrapped_text(&video(),area,font::SIZE_SMALL,font::NORMAL_COLOUR,
00149 _("Recruits: ") + recruit_string.str(),area.x, area.y + 132 + 30 + (leader_rect.h - leader_combo_.height()) / 2,
00150 area.w);
00151 leader_combo_.set_location(leader_rect.x + leader_rect.w + 16, leader_rect.y + (leader_rect.h - leader_combo_.height()) / 2);
00152 gender_combo_.set_location(leader_rect.x + leader_rect.w + 16, gender_rect.y + (gender_rect.h - gender_combo_.height()) / 2);
00153 }
00154 }
00155
00156 bool wait::leader_preview_pane::show_above() const
00157 {
00158 return false;
00159 }
00160
00161 bool wait::leader_preview_pane::left_side() const
00162 {
00163 return false;
00164 }
00165
00166 void wait::leader_preview_pane::set_selection(int selection)
00167 {
00168 selection_ = selection;
00169 leaders_.update_leader_list(selection_);
00170 leaders_.update_gender_list(leaders_.get_leader());
00171 set_dirty();
00172 }
00173
00174 std::string wait::leader_preview_pane::get_selected_leader()
00175 {
00176 return leaders_.get_leader();
00177 }
00178
00179 std::string wait::leader_preview_pane::get_selected_gender()
00180 {
00181 return leaders_.get_gender();
00182 }
00183
00184 handler_vector wait::leader_preview_pane::handler_members() {
00185 handler_vector h;
00186 h.push_back(&leader_combo_);
00187 h.push_back(&gender_combo_);
00188 return h;
00189 }
00190
00191
00192 wait::wait(game_display& disp, const config& cfg,
00193 mp::chat& c, config& gamelist) :
00194 ui(disp, _("Game Lobby"), cfg, c, gamelist),
00195 cancel_button_(disp.video(), _("Cancel")),
00196 start_label_(disp.video(), _("Waiting for game to start..."), font::SIZE_SMALL, font::LOBBY_COLOUR),
00197 game_menu_(disp.video(), std::vector<std::string>(), false, -1, -1, NULL, &gui::menu::bluebg_style),
00198 stop_updates_(false)
00199 {
00200 game_menu_.set_numeric_keypress_selection(false);
00201 gamelist_updated();
00202 }
00203
00204 void wait::process_event()
00205 {
00206 if (cancel_button_.pressed())
00207 set_result(QUIT);
00208 }
00209
00210 void wait::join_game(bool observe)
00211 {
00212 for(;;) {
00213 network::connection data_res = dialogs::network_receive_dialog(disp(),
00214 _("Getting game data..."), level_);
00215 if (!data_res) {
00216 set_result(QUIT);
00217 return;
00218 }
00219 check_response(data_res, level_);
00220 if(level_.child("leave_game")) {
00221 set_result(QUIT);
00222 return;
00223 }
00224
00225
00226
00227 if( (level_.values.find("version") != level_.values.end()) && (level_.child("side") != NULL) )
00228 break;
00229 }
00230
00231
00232 append_to_title(": " + level_["name"]);
00233
00234 if (!observe) {
00235 const config::child_list& sides_list = level_.get_children("side");
00236
00237 if(sides_list.empty()) {
00238 set_result(QUIT);
00239 throw config::error(_("No multiplayer sides available in this game"));
00240 return;
00241 }
00242
00243
00244
00245
00246
00247 int side_choice = 0;
00248 for(config::child_list::const_iterator s = sides_list.begin(); s != sides_list.end(); ++s) {
00249 if((**s)["controller"] == "network" && (**s)["id"].empty()) {
00250 if((**s)["save_id"] == preferences::login() || (**s)["current_player"] == preferences::login()) {
00251 side_choice = s - sides_list.begin();
00252 }
00253 }
00254 }
00255 const bool allow_changes = (*sides_list[side_choice])["allow_changes"] != "no";
00256
00257
00258
00259
00260 std::string leader_choice, gender_choice;
00261 size_t faction_choice = 0;
00262
00263 if(allow_changes) {
00264 events::event_context context;
00265
00266 const config* era = level_.child("era");
00267
00268 if(era == NULL)
00269 throw config::error(_("No era information found."));
00270 const config::child_list& possible_sides =
00271 era->get_children("multiplayer_side");
00272 if(possible_sides.empty()) {
00273 set_result(QUIT);
00274 throw config::error(_("No multiplayer sides found"));
00275 return;
00276 }
00277
00278 std::vector<std::string> choices;
00279 for(config::child_list::const_iterator side =
00280 possible_sides.begin(); side !=
00281 possible_sides.end(); ++side) {
00282 choices.push_back((**side)["name"]);
00283 }
00284
00285 std::vector<gui::preview_pane* > preview_panes;
00286 leader_preview_pane leader_selector(disp(),
00287 possible_sides);
00288 preview_panes.push_back(&leader_selector);
00289
00290 const int res = gui::show_dialog(disp(), NULL, "", _("Choose your side:"),
00291 gui::OK_CANCEL, &choices, &preview_panes);
00292 if(res < 0) {
00293 set_result(QUIT);
00294 return;
00295 }
00296 faction_choice = res;
00297 leader_choice = leader_selector.get_selected_leader();
00298 gender_choice = leader_selector.get_selected_gender();
00299
00300 assert(faction_choice < possible_sides.size());
00301
00302 config faction;
00303 config& change = faction.add_child("change_faction");
00304 change["name"] = preferences::login();
00305 change["faction"] = lexical_cast<std::string>(faction_choice);
00306 change["leader"] = leader_choice;
00307 change["gender"] = gender_choice;
00308 network::send_data(faction, 0, true);
00309 }
00310
00311 }
00312
00313 generate_menu();
00314 }
00315
00316 const game_state& wait::get_state()
00317 {
00318 return state_;
00319 }
00320
00321 void wait::start_game()
00322 {
00323 const config* stats = level_.child("statistics");
00324 if(stats != NULL) {
00325 statistics::fresh_stats();
00326 statistics::read_stats(*stats);
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 if(level_.child("player") == 0) {
00339 level_to_gamestate(level_, state_, level_["savegame"] == "yes");
00340 } else {
00341
00342 state_ = game_state(level_);
00343
00344
00345
00346
00347
00348 if(!state_.scenario.empty() && state_.scenario != "null") {
00349 DBG_NW << "Falling back to loading the old way.\n";
00350 level_to_gamestate(level_, state_, level_["savegame"] == "yes");
00351 }
00352 }
00353
00354 const config* const era_cfg = level_.child("era");
00355 if (era_cfg != NULL && level_["savegame"] != "yes") {
00356 game_events::add_events(era_cfg->get_children("event"),"era_events");
00357 }
00358
00359 LOG_NW << "starting game\n";
00360 }
00361
00362 game_state& wait::request_snapshot(){
00363 config cfg;
00364
00365 cfg.add_child("snapshot_request");
00366
00367 return state_;
00368 }
00369
00370 void wait::layout_children(const SDL_Rect& rect)
00371 {
00372 ui::layout_children(rect);
00373
00374 const SDL_Rect ca = client_area();
00375 int y = ca.y + ca.h - cancel_button_.height();
00376
00377 game_menu_.set_location(ca.x, ca.y + title().height());
00378 game_menu_.set_measurements(ca.w, y - ca.y - title().height()
00379 - gui::ButtonVPadding);
00380 game_menu_.set_max_width(ca.w);
00381 game_menu_.set_max_height(y - ca.y - title().height() - gui::ButtonVPadding);
00382 cancel_button_.set_location(ca.x + ca.w - cancel_button_.width(), y);
00383 start_label_.set_location(ca.x, y + 4);
00384 }
00385
00386 void wait::hide_children(bool hide)
00387 {
00388 ui::hide_children(hide);
00389
00390 cancel_button_.hide(hide);
00391 game_menu_.hide(hide);
00392 }
00393
00394 void wait::process_network_data(const config& data, const network::connection sock)
00395 {
00396 ui::process_network_data(data, sock);
00397
00398 if(data["message"] != "") {
00399
00400 gui::dialog dlg(disp(),_("Response"),data["message"],gui::OK_ONLY);
00401 dlg.show();
00402 }
00403 if(data["failed"] == "yes") {
00404 set_result(QUIT);
00405 return;
00406 } else if(data.child("stop_updates")) {
00407 stop_updates_ = true;
00408 } else if(data.child("start_game")) {
00409 LOG_NW << "received start_game message\n";
00410 set_result(PLAY);
00411 return;
00412 } else if(data.child("leave_game")) {
00413 set_result(QUIT);
00414 return;
00415 } else if(data.child("scenario_diff")) {
00416 LOG_NW << "received diff for scenario... applying...\n";
00417
00418 level_.apply_diff(*data.child("scenario_diff"));
00419 generate_menu();
00420 } else if(data.child("side")) {
00421 level_ = data;
00422 LOG_NW << "got some sides. Current number of sides = "
00423 << level_.get_children("side").size() << ","
00424 << data.get_children("side").size() << "\n";
00425 generate_menu();
00426 }
00427 }
00428
00429 void wait::generate_menu()
00430 {
00431 if (stop_updates_)
00432 return;
00433
00434 std::vector<std::string> details;
00435 std::vector<std::string> playerlist;
00436
00437 const config::child_list& sides = level_.get_children("side");
00438 for(config::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
00439 const config& sd = **s;
00440
00441 if(sd["allow_player"] == "no") {
00442 continue;
00443 }
00444
00445 std::string description = sd["user_description"];
00446 const std::string faction_id = sd["id"];
00447
00448 t_string side_name = sd["name"];
00449 std::string leader_type = sd["type"];
00450 std::string gender_id = sd["gender"];
00451
00452
00453
00454
00455 config::const_child_itors side_units = sd.child_range("unit");
00456 for(;side_units.first != side_units.second; ++side_units.first) {
00457 if(utils::string_bool((**side_units.first)["canrecruit"], false)) {
00458 leader_type = (**side_units.first)["type"];
00459 break;
00460 }
00461 }
00462
00463 if(!sd["id"].empty())
00464 playerlist.push_back(sd["id"]);
00465
00466 std::string leader_name;
00467 std::string leader_image;
00468 unit_type_data::unit_type_map_wrapper& utypes = unit_type_data::types();
00469 const unit_type* ut;
00470 const unit_type* utg;
00471
00472 if (utypes.find(leader_type) != utypes.end() && leader_type != "random") {
00473 ut = &(utypes.find(leader_type)->second);
00474 if (!gender_id.empty()) {
00475 if (gender_id == "female")
00476 utg = &(ut->get_gender_unit_type(unit_race::FEMALE));
00477 else
00478
00479
00480 utg = &(ut->get_gender_unit_type(unit_race::MALE));
00481 } else
00482 utg = ut;
00483
00484 leader_name = utg->type_name();
00485 #ifdef LOW_MEM
00486 leader_image = utg->image();
00487 #else
00488 leader_image = utg->image() + std::string("~RC(") + std::string(utg->flag_rgb() + ">" + sd["side"] + ")");
00489 #endif
00490 } else {
00491 leader_image = leader_list_manager::random_enemy_picture;
00492 }
00493 if (!leader_image.empty()) {
00494
00495
00496 if(side_name.str()[0] == font::IMAGE) {
00497 std::string::size_type p =
00498 side_name.str().find_first_of(COLUMN_SEPARATOR);
00499 if(p != std::string::npos && p < side_name.size()) {
00500 side_name = IMAGE_PREFIX + leader_image + COLUMN_SEPARATOR + side_name.str().substr(p+1);
00501 }
00502 }
00503 }
00504
00505 std::stringstream str;
00506 str << sd["side"] << ". " << COLUMN_SEPARATOR;
00507 str << description << COLUMN_SEPARATOR << side_name << COLUMN_SEPARATOR;
00508
00509 if(!leader_name.empty())
00510 str << _("(") << leader_name << _(")");
00511 str << COLUMN_SEPARATOR;
00512
00513 if(sd["allow_changes"] == "yes")
00514 str << sd["gold"] << ' ' << _("Gold") << COLUMN_SEPARATOR;
00515
00516 int income_amt = lexical_cast_default<int>(sd["income"], 0);
00517 if(income_amt != 0){
00518 str << _("(") << _("Income") << ' ';
00519 if(income_amt > 0)
00520 str << _("+");
00521 str << sd["income"] << _(")");
00522 }
00523
00524 str << COLUMN_SEPARATOR << sd["user_team_name"];
00525 int disp_color = lexical_cast_default<int>(sd["colour"], 0) - 1;
00526 if(!sd["colour"].empty()) {
00527 try {
00528 disp_color = game_config::color_info(sd["colour"]).index() - 1;
00529 } catch(config::error&) {
00530
00531 }
00532 } else {
00533
00534
00535 disp_color = lexical_cast_default<int>(sd["side"], 0) - 1;
00536 }
00537 str << COLUMN_SEPARATOR << get_colour_string(disp_color);
00538 details.push_back(str.str());
00539 }
00540
00541 game_menu_.set_items(details);
00542
00543
00544
00545 if (gamelist().child("user") == NULL) {
00546 set_user_list(playerlist, true);
00547 }
00548 }
00549
00550 }
00551