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