00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "ai.hpp"
00021 #include "dialogs.hpp"
00022 #include "font.hpp"
00023 #include "game_config.hpp"
00024 #include "game_events.hpp"
00025 #include "game_preferences.hpp"
00026 #include "gettext.hpp"
00027 #include "log.hpp"
00028 #include "multiplayer_connect.hpp"
00029 #include "statistics.hpp"
00030 #include "show_dialog.hpp"
00031 #include "serialization/string_utils.hpp"
00032
00033 #include <cassert>
00034
00035 #define LOG_NW LOG_STREAM(info, network)
00036 #define ERR_NW LOG_STREAM(err, network)
00037 #define LOG_CF LOG_STREAM(info, config)
00038 #define WRN_CF LOG_STREAM(warn, config)
00039 #define ERR_CF LOG_STREAM(err, config)
00040
00041 namespace {
00042 const char* controller_names[] = {
00043 "network",
00044 "human",
00045 "ai",
00046 "null"
00047 };
00048 }
00049
00050 namespace mp {
00051
00052 connect::side::side(connect& parent, const config& cfg, int index) :
00053 parent_(&parent),
00054 cfg_(cfg),
00055 index_(index),
00056 id_(""),
00057 save_id_(cfg_.get_attribute("save_id")),
00058 controller_(),
00059 faction_(lexical_cast_default<int>(cfg_.get_attribute("faction"), 0)),
00060 team_(0),
00061 colour_(index),
00062 gold_(lexical_cast_default<int>(cfg_.get_attribute("gold"), 100)),
00063 income_(lexical_cast_default<int>(cfg_.get_attribute("income"), 0)),
00064 leader_(),
00065 gender_(),
00066 ai_algorithm_(),
00067 player_number_(parent.video(), lexical_cast_default<std::string>(index+1, ""),
00068 font::SIZE_LARGE, font::LOBBY_COLOUR),
00069 combo_controller_(parent.disp(), parent.player_types_),
00070 orig_controller_(parent.video(), cfg.get_attribute("id"), font::SIZE_SMALL),
00071 combo_ai_algorithm_(parent.disp(), std::vector<std::string>()),
00072 combo_faction_(parent.disp(), parent.player_factions_),
00073 combo_leader_(parent.disp(), std::vector<std::string>()),
00074 combo_gender_(parent.disp(), std::vector<std::string>()),
00075 combo_team_(parent.disp(), parent.player_teams_),
00076 combo_colour_(parent.disp(), parent.player_colours_),
00077 slider_gold_(parent.video()),
00078 slider_income_(parent.video()),
00079 label_gold_(parent.video(), "100", font::SIZE_SMALL, font::LOBBY_COLOUR),
00080 label_income_(parent.video(), _("Normal"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00081 allow_player_(utils::string_bool(cfg_.get_attribute("allow_player"), true)),
00082 enabled_(!parent_->params_.saved_game), changed_(false),
00083 llm_(parent.era_sides_, enabled_ ? &combo_leader_ : NULL, enabled_ ? &combo_gender_ : NULL)
00084 {
00085 if(allow_player_ && enabled_) {
00086 controller_ = parent_->default_controller_;
00087 } else {
00088 size_t i = CNTR_NETWORK;
00089
00090 if (!allow_player_)
00091 {
00092 cfg_["controller"] = controller_names[CNTR_COMPUTER];
00093 controller_ = static_cast<mp::controller>(CNTR_COMPUTER);
00094 }
00095 else
00096 {
00097 for(; i != CNTR_LAST; ++i) {
00098 if(cfg_["controller"] == controller_names[i]) {
00099 controller_ = static_cast<mp::controller>(i);
00100 break;
00101 }
00102 }
00103 }
00104 }
00105
00106 slider_gold_.set_min(20);
00107 slider_gold_.set_max(800);
00108 slider_gold_.set_increment(25);
00109 slider_gold_.set_value(lexical_cast_default<int>(cfg_.get_attribute("gold"), 100));
00110 slider_gold_.set_measurements(80, 16);
00111
00112 slider_income_.set_min(-2);
00113 slider_income_.set_max(18);
00114 slider_income_.set_increment(1);
00115 slider_income_.set_value(lexical_cast_default<int>(cfg_.get_attribute("income"), 0));
00116 slider_income_.set_measurements(50, 16);
00117
00118 combo_faction_.enable(enabled_);
00119 combo_leader_.enable(enabled_);
00120 combo_gender_.enable(enabled_);
00121 combo_team_.enable(enabled_);
00122 combo_colour_.enable(enabled_);
00123 slider_gold_.hide(!enabled_);
00124 slider_income_.hide(!enabled_);
00125 label_gold_.hide(!enabled_);
00126 label_income_.hide(!enabled_);
00127
00128 std::vector<std::string>::const_iterator itor =
00129 std::find(parent_->team_names_.begin(), parent_->team_names_.end(),
00130 cfg_.get_attribute("team_name"));
00131 if(itor == parent_->team_names_.end()) {
00132 assert(!parent_->team_names_.empty());
00133 team_ = 0;
00134 } else {
00135 team_ = itor - parent_->team_names_.begin();
00136 }
00137 if(!cfg_.get_attribute("colour").empty()) {
00138 colour_ = game_config::color_info(cfg_["colour"]).index() - 1;
00139 }
00140 config *ai = cfg_.child("ai");
00141 if (ai)
00142 ai_algorithm_ = lexical_cast_default<std::string>((*ai)["ai_algorithm"], "default");
00143 else
00144 ai_algorithm_ = "default";
00145 init_ai_algorithm_combo();
00146
00147
00148 if (!enabled_) {
00149 faction_ = 0;
00150 std::vector<std::string> pseudo_factions;
00151 pseudo_factions.push_back(cfg_["name"]);
00152 combo_faction_.set_items(pseudo_factions);
00153 combo_faction_.set_selected(0);
00154
00155
00156
00157 config::const_child_itors side_units = cfg.child_range("unit");
00158 std::string leader_type;
00159 for(;side_units.first != side_units.second; ++side_units.first) {
00160 if(utils::string_bool((**side_units.first)["canrecruit"], false)) {
00161 leader_type = (**side_units.first)["type"];
00162 gender_ = (**side_units.first)["gender"];
00163 break;
00164 }
00165 }
00166 std::vector<std::string> leader_name_pseudolist;
00167 if(leader_type.empty()) {
00168 leader_name_pseudolist.push_back("-");
00169 } else {
00170 unit_type_data::unit_type_map::const_iterator leader_name =
00171 unit_type_data::types().find(leader_type);
00172 if(leader_name == unit_type_data::types().end()) {
00173 leader_name_pseudolist.push_back("-");
00174 } else {
00175 if (gender_ == "female")
00176 leader_name_pseudolist.push_back(leader_name->second.get_gender_unit_type(unit_race::FEMALE).type_name());
00177 else if (gender_ == "male")
00178 leader_name_pseudolist.push_back(leader_name->second.get_gender_unit_type(unit_race::MALE).type_name());
00179 else
00180 leader_name_pseudolist.push_back(leader_name->second.type_name());
00181 }
00182 }
00183 combo_leader_.set_items(leader_name_pseudolist);
00184 combo_leader_.set_selected(0);
00185 std::vector<std::string> gender_name_pseudolist;
00186
00187 if (!gender_.empty()) {
00188 if (leader_type.empty()
00189 || unit_type_data::types().find(leader_type)
00190 == unit_type_data::types().end())
00191 {
00192 gender_name_pseudolist.push_back("-");
00193 } else {
00194 if (gender_ == "female")
00195 gender_name_pseudolist.push_back( _("Female ♀") );
00196 else if (gender_ == "male")
00197 gender_name_pseudolist.push_back( _("Male ♂") );
00198 else if (gender_ == "random")
00199 gender_name_pseudolist.push_back( _("gender^Random") );
00200 else gender_name_pseudolist.push_back("?");
00201 }
00202 } else {
00203 gender_name_pseudolist.push_back("-");
00204 }
00205 combo_gender_.set_items(gender_name_pseudolist);
00206 combo_gender_.set_selected(0);
00207 } else if(parent_->params_.use_map_settings) {
00208
00209 if(utils::string_bool(cfg_.get_attribute("gold_lock"), false)) {
00210 slider_gold_.enable(false);
00211 label_gold_.enable(false);
00212 }
00213 if(utils::string_bool(cfg_.get_attribute("income_lock"), false)) {
00214 slider_income_.enable(false);
00215 label_income_.enable(false);
00216 }
00217 if(utils::string_bool(cfg_.get_attribute("team_lock"), false)) {
00218 combo_team_.enable(false);
00219 }
00220 if(utils::string_bool(cfg_.get_attribute("colour_lock"), false)) {
00221 combo_colour_.enable(false);
00222 }
00223
00224
00225 leader_ = cfg_.get_attribute("type");
00226 gender_ = cfg_.get_attribute("gender");
00227 if(!leader_.empty()) {
00228 combo_leader_.enable(false);
00229 combo_gender_.enable(false);
00230 llm_.set_leader_combo(NULL);
00231 llm_.set_gender_combo(NULL);
00232 std::vector<std::string> leader_name_pseudolist;
00233 unit_type_data::unit_type_map::const_iterator leader_name = unit_type_data::types().find(leader_);
00234 if(leader_name == unit_type_data::types().end()) {
00235 leader_name_pseudolist.push_back("?");
00236 } else {
00237 leader_name_pseudolist.push_back(leader_name->second.type_name());
00238 }
00239 combo_leader_.set_items(leader_name_pseudolist);
00240 combo_leader_.set_selected(0);
00241 std::vector<std::string> gender_name_pseudolist;
00242 if (!gender_.empty()) {
00243 if(leader_name == unit_type_data::types().end()) {
00244 gender_name_pseudolist.push_back("?");
00245 } else {
00246 if (gender_ == "female")
00247 gender_name_pseudolist.push_back( _("Female ♀") );
00248 else if (gender_ == "male")
00249 gender_name_pseudolist.push_back( _("Male ♂") );
00250 else if (gender_ == "random")
00251 gender_name_pseudolist.push_back( _("gender^Random") );
00252 else gender_name_pseudolist.push_back("?");
00253 }
00254 } else gender_name_pseudolist.push_back("?");
00255 combo_gender_.set_items(gender_name_pseudolist);
00256 combo_gender_.set_selected(0);
00257 }
00258
00259
00260
00261 if(faction_ == 0) {
00262 std::vector<std::string> find;
00263 std::string search_field;
00264 if(!cfg_.get_attribute("faction").empty()) {
00265
00266 find.push_back(cfg_["faction"]);
00267 search_field = "id";
00268 } else if(utils::string_bool(cfg["faction_from_recruit"]) && !cfg_.get_attribute("recruit").empty()) {
00269
00270 find = utils::split(cfg_["recruit"]);
00271 search_field = "recruit";
00272 } else if(!leader_.empty()) {
00273
00274 find.push_back(leader_);
00275 search_field = "leader";
00276 }
00277
00278 int faction_index = 0;
00279 int best_score = 0;
00280 std::vector<config*>::const_iterator faction = parent.era_sides_.begin();
00281 while(faction != parent.era_sides_.end()) {
00282 int faction_score = 0;
00283 const config& side = (**faction);
00284 std::vector<std::string> recruit;
00285 recruit = utils::split(side[search_field]);
00286 std::vector<std::string>::const_iterator search = find.begin();
00287 while(search != find.end()) {
00288 for(itor = recruit.begin(); itor != recruit.end(); ++itor) {
00289 if(*itor == *search) {
00290 faction_score++;
00291 break;
00292 }
00293 }
00294 ++search;
00295 }
00296 if(faction_score > best_score) {
00297 best_score = faction_score;
00298 faction_ = faction_index;
00299 }
00300 ++faction;
00301 faction_index++;
00302 }
00303 if (faction_) {
00304 llm_.update_leader_list(faction_);
00305 llm_.update_gender_list(llm_.get_leader());
00306 combo_faction_.enable(false);
00307 }
00308 } else {
00309 combo_faction_.enable(false);
00310 }
00311 }
00312
00313 update_ui();
00314 }
00315
00316 connect::side::side(const side& a) :
00317 parent_(a.parent_), cfg_(a.cfg_),
00318 index_(a.index_), id_(a.id_), save_id_(a.save_id_),
00319 controller_(a.controller_),
00320 faction_(a.faction_), team_(a.team_), colour_(a.colour_),
00321 gold_(a.gold_), income_(a.income_), leader_(a.leader_),
00322 gender_(a.gender_),
00323 ai_algorithm_(a.ai_algorithm_),
00324 player_number_(a.player_number_), combo_controller_(a.combo_controller_),
00325 orig_controller_(a.orig_controller_),
00326 combo_ai_algorithm_(a.combo_ai_algorithm_),
00327 combo_faction_(a.combo_faction_), combo_leader_(a.combo_leader_), combo_gender_(a.combo_gender_),
00328 combo_team_(a.combo_team_), combo_colour_(a.combo_colour_),
00329 slider_gold_(a.slider_gold_), slider_income_(a.slider_income_),
00330 label_gold_(a.label_gold_), label_income_(a.label_income_),
00331 allow_player_(a.allow_player_), enabled_(a.enabled_),
00332 changed_(a.changed_), llm_(a.llm_)
00333 {
00334 llm_.set_leader_combo((enabled_ && leader_.empty()) ? &combo_leader_ : NULL);
00335 llm_.set_gender_combo((enabled_ && leader_.empty()) ? &combo_gender_ : NULL);
00336
00337
00338 llm_.update_gender_list(llm_.get_leader());
00339 }
00340
00341 void connect::side::add_widgets_to_scrollpane(gui::scrollpane& pane, int pos)
00342 {
00343 pane.add_widget(&player_number_, 0, 5 + pos);
00344 pane.add_widget(&combo_controller_, 20, 5 + pos);
00345 pane.add_widget(&orig_controller_, 20 + (combo_controller_.width() - orig_controller_.width()) / 2,
00346 35 + pos + (combo_leader_.height() - orig_controller_.height()) / 2);
00347 pane.add_widget(&combo_ai_algorithm_, 20, 35 + pos);
00348 pane.add_widget(&combo_faction_, 135, 5 + pos);
00349 pane.add_widget(&combo_leader_, 135, 35 + pos);
00350 pane.add_widget(&combo_gender_, 250, 35 + pos);
00351 pane.add_widget(&combo_team_, 250, 5 + pos);
00352 pane.add_widget(&combo_colour_, 365, 5 + pos);
00353 pane.add_widget(&slider_gold_, 475, 5 + pos);
00354 pane.add_widget(&label_gold_, 475, 35 + pos);
00355 pane.add_widget(&slider_income_, 475 + slider_gold_.width(), 5 + pos);
00356 pane.add_widget(&label_income_, 475 + slider_gold_.width(), 35 + pos);
00357 }
00358
00359 void connect::side::process_event()
00360 {
00361 if(combo_controller_.changed() && combo_controller_.selected() >= 0) {
00362 if (combo_controller_.selected() == CNTR_LAST) {
00363 update_controller_ui();
00364 } else if (combo_controller_.selected() < CNTR_LAST) {
00365
00366
00367
00368
00369 controller_ = mp::controller(combo_controller_.selected());
00370
00371
00372 if(!id_.empty()) {
00373 if (id_ != preferences::login()) {
00374 parent_->kick_player(id_);
00375 }
00376 id_ = "";
00377 }
00378 changed_ = true;
00379 } else {
00380 size_t user = combo_controller_.selected() - CNTR_LAST - 1;
00381
00382
00383
00384
00385
00386 const std::string new_id = parent_->users_[user].name;
00387 if (new_id != id_) {
00388 int old_side = parent_->find_player_side(new_id);
00389 if (old_side != -1) {
00390 if (id_.empty()) {
00391 parent_->sides_[old_side].set_controller(parent_->default_controller_);
00392 } else {
00393 parent_->sides_[old_side].set_id(id_);
00394 }
00395 }
00396 id_ = new_id;
00397 controller_ = parent_->users_[user].controller;
00398 changed_ = true;
00399 }
00400 }
00401 update_ai_algorithm_combo();
00402 }
00403
00404 if(!enabled_)
00405 return;
00406
00407 if (combo_faction_.changed() && combo_faction_.selected() >= 0) {
00408 faction_ = combo_faction_.selected();
00409 llm_.update_leader_list(faction_);
00410 llm_.update_gender_list(llm_.get_leader());
00411 changed_ = true;
00412 }
00413 if (combo_ai_algorithm_.changed() && combo_ai_algorithm_.selected() >= 0) {
00414 ai_algorithm_ = parent_->ai_algorithms_[combo_ai_algorithm_.selected()];
00415 changed_ = true;
00416 }
00417 if (combo_leader_.changed() && combo_leader_.selected() >= 0) {
00418 llm_.update_gender_list(llm_.get_leader());
00419 changed_ = true;
00420 }
00421 if (combo_gender_.changed() && combo_gender_.selected() >= 0) {
00422 llm_.set_leader_combo(&combo_leader_);
00423 changed_ = true;
00424 }
00425 if (combo_team_.changed() && combo_team_.selected() >= 0) {
00426 team_ = combo_team_.selected();
00427 changed_ = true;
00428 }
00429 if (combo_colour_.changed() && combo_colour_.selected() >= 0) {
00430 colour_ = combo_colour_.selected();
00431 changed_ = true;
00432 }
00433 if (slider_gold_.value() != gold_) {
00434 gold_ = slider_gold_.value();
00435 label_gold_.set_text(lexical_cast_default<std::string>(gold_, "0"));
00436 changed_ = true;
00437 }
00438 if (slider_income_.value() != income_) {
00439
00440 income_ = slider_income_.value();
00441 std::stringstream buf;
00442 if(income_ < 0) {
00443 buf << _("(") << income_ << _(")");
00444 } else if(income_ > 0) {
00445 buf << _("+") << income_;
00446 } else {
00447 buf << _("Normal");
00448 }
00449 label_income_.set_text(buf.str());
00450 changed_ = true;
00451 }
00452 }
00453
00454 bool connect::side::changed()
00455 {
00456 bool res = changed_;
00457 changed_ = false;
00458 return res;
00459 }
00460
00461 bool connect::side::available() const
00462 {
00463 return allow_player_ && controller_ == CNTR_NETWORK && id_.empty();
00464 }
00465
00466 bool connect::side::allow_player() const
00467 {
00468 return allow_player_;
00469 }
00470
00471 void connect::side::update_controller_ui()
00472 {
00473 if (id_.empty()) {
00474 combo_controller_.set_selected(controller_);
00475 } else {
00476 connected_user_list::iterator player = parent_->find_player(id_);
00477
00478 if (player != parent_->users_.end()) {
00479 combo_controller_.set_selected(CNTR_LAST + 1 + (player - parent_->users_.begin()));
00480 } else {
00481 combo_controller_.set_selected(CNTR_NETWORK);
00482 }
00483 }
00484
00485 update_ai_algorithm_combo();
00486 }
00487
00488 void connect::side::hide_ai_algorithm_combo(bool invis)
00489 {
00490 if(!invis)
00491 {
00492 if(controller_ == CNTR_COMPUTER)
00493 {
00494
00495 orig_controller_.hide(true);
00496 combo_ai_algorithm_.hide(false);
00497 } else {
00498
00499 combo_ai_algorithm_.hide(true);
00500 orig_controller_.hide(false);
00501 }
00502 } else {
00503 combo_ai_algorithm_.hide(true);
00504 }
00505 }
00506
00507 void connect::side::init_ai_algorithm_combo()
00508 {
00509 assert(parent_->ai_algorithms_.empty() == false);
00510
00511 int sel = 0;
00512 std::vector<std::string> ais = parent_->ai_algorithms_;
00513 for (unsigned int i = 0; i < ais.size(); i++) {
00514 if (ais[i] == ai_algorithm_) {
00515 sel = i;
00516 }
00517 if (ais[i] == "default") {
00518 ais[i] = _("Default AI");
00519 }
00520 }
00521 combo_ai_algorithm_.set_items(ais);
00522 combo_ai_algorithm_.set_selected(sel);
00523 }
00524
00525 void connect::side::update_ui()
00526 {
00527 update_controller_ui();
00528
00529 if (combo_faction_.selected() != faction_ && combo_faction_.selected() >= 0) {
00530 combo_faction_.set_selected(faction_);
00531 }
00532
00533 combo_team_.set_selected(team_);
00534 combo_colour_.set_selected(colour_);
00535 slider_gold_.set_value(gold_);
00536 label_gold_.set_text(lexical_cast_default<std::string>(gold_, "0"));
00537 slider_income_.set_value(income_);
00538 std::stringstream buf;
00539 if(income_ < 0) {
00540 buf << _("(") << income_ << _(")");
00541 } else if(income_ > 0) {
00542 buf << _("+") << income_;
00543 } else {
00544 buf << _("Normal");
00545 }
00546 label_income_.set_text(buf.str());
00547 }
00548
00549 config connect::side::get_config() const
00550 {
00551 config res(cfg_);
00552
00553
00554
00555 if(enabled_ && !parent_->era_sides_.empty()) {
00556
00557 res.append(*(parent_->era_sides_[faction_]));
00558 }
00559 if (cfg_.get_attribute("side").empty()
00560 || cfg_["side"] != lexical_cast<std::string>(index_ + 1))
00561 {
00562 res["side"] = lexical_cast<std::string>(index_ + 1);
00563 }
00564 res["controller"] = controller_names[controller_];
00565 res["id"] = id_;
00566 res["current_player"] = id_;
00567
00568 if (id_.empty()) {
00569 char const *description;
00570 switch(controller_) {
00571 case CNTR_NETWORK:
00572 description = N_("(Vacant slot)");
00573 break;
00574 case CNTR_LOCAL:
00575 if(enabled_ && cfg_.get_attribute("save_id").empty()) {
00576 res["save_id"] = "local" + res["side"].str();
00577 }
00578 description = N_("Anonymous local player");
00579 break;
00580 case CNTR_COMPUTER:
00581 if(enabled_ && cfg_.get_attribute("save_id").empty()) {
00582 res["save_id"] = "ai" + res["side"].str();
00583 }
00584 {
00585 config *ai = res.child("ai");
00586 if (!ai) ai = &res.add_child("ai");
00587 #ifdef HAVE_PYTHON
00588 if (ai_algorithm_.substr(ai_algorithm_.length() - 3) == ".py") {
00589 (*ai)["ai_algorithm"] = "python_ai";
00590 (*ai)["python_script"] = ai_algorithm_;
00591 }
00592 else
00593 #endif
00594 {
00595 if (ai_algorithm_ != "default")
00596 (*ai)["ai_algorithm"] = ai_algorithm_;
00597 }
00598 }
00599 description = N_("Computer player");
00600 break;
00601 case CNTR_EMPTY:
00602 description = N_("(Empty slot)");
00603 res["no_leader"] = "yes";
00604 break;
00605 default:
00606 assert(false);
00607 break;
00608 }
00609 res["user_description"] = t_string(description, "wesnoth");
00610 } else {
00611 if(enabled_ && cfg_.get_attribute("save_id").empty()) {
00612 res["save_id"] = id_;
00613 }
00614
00615 res["user_description"] = id_;
00616 }
00617
00618 if(enabled_) {
00619 if (leader_.empty()) {
00620 res["type"] = llm_.get_leader();
00621 } else {
00622 res["type"] = leader_;
00623 }
00624 if (gender_.empty()) {
00625 std::string dummy = llm_.get_gender();
00626 if (!dummy.empty() && dummy != "null" && dummy != "?")
00627 res["gender"] = dummy;
00628 } else {
00629
00630
00631 if (gender_ != "null")
00632 res["gender"] = gender_;
00633 }
00634
00635 res["team_name"] = parent_->team_names_[team_];
00636 res["user_team_name"] = parent_->user_team_names_[team_];
00637 res["allow_player"] = allow_player_ ? "yes" : "no";
00638 res["colour"] = lexical_cast<std::string>(colour_ + 1);
00639 res["gold"] = lexical_cast<std::string>(gold_);
00640 res["income"] = lexical_cast<std::string>(income_);
00641
00642 if(!parent_->params_.use_map_settings || res["fog"].empty() || (res["fog"] != "yes" && res["fog"] != "no")) {
00643 res["fog"] = parent_->params_.fog_game ? "yes" : "no";
00644 }
00645
00646 if(!parent_->params_.use_map_settings || res["shroud"].empty() || (res["shroud"] != "yes" && res["shroud"] != "no")) {
00647 res["shroud"] = parent_->params_.shroud_game ? "yes" : "no";
00648 }
00649
00650
00651 if(!parent_->params_.use_map_settings || res["mp_countdown"].empty() || (res["mp_countdown"] != "yes" && res["mp_countdown"] != "no")) {
00652 res["mp_countdown"] = parent_->params_.mp_countdown ? "yes" : "no";;
00653 }
00654
00655 if(!parent_->params_.use_map_settings || res["mp_countdown_init_time"].empty()) {
00656 res["mp_countdown_init_time"] = lexical_cast<std::string>(parent_->params_.mp_countdown_init_time);
00657 }
00658 if(!parent_->params_.use_map_settings || res["mp_countdown_turn_bonus"].empty()) {
00659 res["mp_countdown_turn_bonus"] = lexical_cast<std::string>(parent_->params_.mp_countdown_turn_bonus);
00660 }
00661 if(!parent_->params_.use_map_settings || res["mp_countdown_reservoir_time"].empty()) {
00662 res["mp_countdown_reservoir_time"] = lexical_cast<std::string>(parent_->params_.mp_countdown_reservoir_time);
00663 }
00664 if(!parent_->params_.use_map_settings || res["mp_countdown_action_bonus"].empty()) {
00665 res["mp_countdown_action_bonus"] = lexical_cast<std::string>(parent_->params_.mp_countdown_action_bonus);
00666 }
00667
00668 res["share_maps"] = parent_->params_.share_maps ? "yes" : "no";
00669 res["share_view"] = parent_->params_.share_view ? "yes" : "no";
00670 if(!parent_->params_.use_map_settings || res["village_gold"].empty())
00671 res["village_gold"] = lexical_cast<std::string>(parent_->params_.village_gold);
00672
00673 res["allow_changes"] = "yes";
00674 } else {
00675 res["allow_changes"] = "no";
00676 }
00677
00678 if(parent_->params_.use_map_settings && enabled_) {
00679 config trimmed = cfg_;
00680 trimmed["side"] = "";
00681 trimmed["controller"] = "";
00682 trimmed["id"] = "";
00683 trimmed["team_name"] = "";
00684 trimmed["user_team_name"] = "";
00685 trimmed["colour"] = "";
00686 trimmed["gold"] = "";
00687 trimmed["income"] = "";
00688 trimmed["allow_changes"] = "";
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 if(controller_ != CNTR_COMPUTER) {
00700
00701 trimmed["user_description"] = "";
00702 }
00703 trimmed.prune();
00704 res.merge_with(trimmed);
00705 }
00706 return res;
00707 }
00708
00709 void connect::side::set_controller(mp::controller controller)
00710 {
00711 controller_ = controller;
00712 id_ = "";
00713
00714 update_ui();
00715 }
00716
00717 mp::controller connect::side::get_controller() const
00718 {
00719 return controller_;
00720 }
00721
00722 void connect::side::update_user_list()
00723 {
00724 bool name_present = false;
00725
00726 std::vector<std::string> list = parent_->player_types_;
00727 list.push_back("----");
00728
00729 connected_user_list::const_iterator itor;
00730 for (itor = parent_->users_.begin(); itor != parent_->users_.end();
00731 ++itor) {
00732 list.push_back(itor->name);
00733 if (itor->name == id_)
00734 name_present = true;
00735 }
00736
00737 if (name_present == false) {
00738 id_ = "";
00739 }
00740
00741 combo_controller_.set_items(list);
00742 update_controller_ui();
00743 }
00744
00745 const std::string& connect::side::get_id() const
00746 {
00747 return id_;
00748 }
00749
00750 void connect::side::set_id(const std::string& id)
00751 {
00752 connected_user_list::iterator i = parent_->find_player(id);
00753 if (i != parent_->users_.end()) {
00754 id_ = id;
00755 controller_ = i->controller;
00756 }
00757 update_ui();
00758 }
00759
00760 const std::string& connect::side::get_save_id() const
00761 {
00762 return save_id_;
00763 }
00764
00765 void connect::side::import_network_user(const config& data)
00766 {
00767 id_ = data["name"];
00768 controller_ = CNTR_NETWORK;
00769
00770 if(enabled_ && !parent_->era_sides_.empty()) {
00771 if(combo_faction_.enabled()) {
00772 faction_ = lexical_cast_default<int>(data["faction"], 0);
00773 if(faction_ > int(parent_->era_sides_.size()))
00774 faction_ = 0;
00775 llm_.update_leader_list(faction_);
00776 llm_.update_gender_list(llm_.get_leader());
00777 }
00778 if(combo_leader_.enabled()) {
00779 llm_.set_leader(data["leader"]);
00780
00781
00782 llm_.update_gender_list(llm_.get_leader());
00783 }
00784 if (combo_gender_.enabled()) {
00785 llm_.set_gender(data["gender"]);
00786 }
00787 }
00788
00789 update_ui();
00790 }
00791
00792 void connect::side::reset(mp::controller controller)
00793 {
00794 id_ = "";
00795 controller_ = controller;
00796
00797 if(enabled_ && !parent_->era_sides_.empty()) {
00798 if(combo_faction_.enabled())
00799 faction_ = 0;
00800 if(combo_leader_.enabled())
00801 llm_.update_leader_list(0);
00802 if (combo_gender_.enabled())
00803 llm_.update_gender_list(llm_.get_leader());
00804 }
00805
00806 update_ui();
00807 }
00808
00809 void connect::side::resolve_random()
00810 {
00811 if(!enabled_ || parent_->era_sides_.empty())
00812 return;
00813
00814 if(utils::string_bool(
00815 (*parent_->era_sides_[faction_]).get_attribute("random_faction"),
00816 false))
00817 {
00818 std::vector<std::string> faction_choices, faction_excepts;
00819 faction_choices = utils::split((*parent_->era_sides_[faction_]).get_attribute("choices"));
00820 if(faction_choices.size() == 1 && faction_choices.front() == "") {
00821 faction_choices.clear();
00822 }
00823 faction_excepts = utils::split((*parent_->era_sides_[faction_]).get_attribute("except"));
00824 if(faction_excepts.size() == 1 && faction_excepts.front() == "") {
00825 faction_excepts.clear();
00826 }
00827
00828
00829 std::vector<int> nonrandom_sides;
00830 for(config::child_iterator itor = parent_->era_sides_.begin();
00831 itor != parent_->era_sides_.end(); ++itor) {
00832 if((**itor)["random_faction"] != "yes") {
00833 const std::string& faction_id = (**itor)["id"];
00834 if (
00835 !faction_choices.empty() &&
00836 std::find(faction_choices.begin(),faction_choices.end(),faction_id) == faction_choices.end()
00837 )
00838 continue;
00839 if (
00840 !faction_excepts.empty() &&
00841 std::find(faction_excepts.begin(),faction_excepts.end(),faction_id) != faction_excepts.end()
00842 )
00843 continue;
00844 nonrandom_sides.push_back(itor - parent_->era_sides_.begin());
00845 }
00846 }
00847
00848 if (nonrandom_sides.size() == 0) {
00849 throw config::error(_("Only random sides in the current era."));
00850 }
00851
00852 faction_ = nonrandom_sides[rand() % nonrandom_sides.size()];
00853 }
00854 bool solved_random_leader = false;
00855
00856 if (llm_.get_leader() == "random") {
00857
00858 llm_.set_gender("random");
00859 const config& fact = *parent_->era_sides_[faction_];
00860 std::vector<std::string> types = utils::split(fact["random_leader"]);
00861 if (!types.empty()) {
00862 const int lchoice = rand() % types.size();
00863 leader_ = types[lchoice];
00864 } else {
00865
00866 types = utils::split(fact["leader"]);
00867 if (!types.empty()) {
00868 const int lchoice = rand() % types.size();
00869 leader_ = types[lchoice];
00870 } else {
00871 utils::string_map i18n_symbols;
00872 i18n_symbols["faction"] = fact["name"];
00873 throw config::error(vgettext("Unable to find a leader type for faction $faction", i18n_symbols));
00874 }
00875 }
00876 solved_random_leader = true;
00877 }
00878
00879 if (llm_.get_gender() == "random" || solved_random_leader) {
00880 unit_type_data::unit_type_map::const_iterator ut = unit_type_data::types().find(leader_.empty() ? llm_.get_leader() : leader_);
00881
00882 if (ut != unit_type_data::types().end()) {
00883 const std::vector<unit_race::GENDER> glist = ut->second.genders();
00884 if (!glist.empty()) {
00885 const int gchoice = rand() % glist.size();
00886
00887 unit_race::GENDER sgender = glist[gchoice];
00888 switch (sgender)
00889 {
00890 case unit_race::FEMALE:
00891 gender_ = "female";
00892 break;
00893 case unit_race::MALE:
00894 gender_ = "male";
00895 break;
00896 default:
00897 gender_ = "null";
00898 }
00899 } else gender_ = "null";
00900 } else {
00901 ERR_CF << "cannot obtain genders for invalid leader '" << (leader_.empty() ? llm_.get_leader() : leader_) << "'.\n";
00902 gender_ = "null";
00903 }
00904 }
00905 }
00906
00907 connect::connect(game_display& disp, const config& game_config,
00908 chat& c, config& gamelist, const create::parameters& params,
00909 mp::controller default_controller) :
00910 mp::ui(disp, _("Game Lobby: ") + params.name, game_config, c, gamelist),
00911 level_(),
00912 state_(),
00913 params_(params),
00914 era_sides_(),
00915 player_types_(),
00916 player_factions_(),
00917 player_teams_(),
00918 player_colours_(),
00919 ai_algorithms_(),
00920 team_names_(),
00921 user_team_names_(),
00922 team_prefix_(std::string(_("Team")) + " "),
00923 sides_(),
00924 users_(),
00925 waiting_label_(video(), "", font::SIZE_SMALL, font::LOBBY_COLOUR),
00926 message_full_(false),
00927 default_controller_(default_controller),
00928 scroll_pane_(video()),
00929 type_title_label_(video(), _("Player/Type"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00930 faction_title_label_(video(), _("Faction"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00931 team_title_label_(video(), _("Team/Gender"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00932 colour_title_label_(video(), _("Color"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00933 gold_title_label_(video(), _("Gold"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00934 income_title_label_(video(), _("Income"), font::SIZE_SMALL, font::LOBBY_COLOUR),
00935
00936 launch_(video(), _("I'm Ready")),
00937 cancel_(video(), _("Cancel"))
00938 {
00939 load_game();
00940
00941 if(get_result() == QUIT
00942 || get_result() == CREATE)
00943 return;
00944 lists_init();
00945 if(sides_.empty()) {
00946 throw config::error(_("The scenario is invalid because it has no sides."));
00947 }
00948
00949 config response;
00950 config& create_game = response.add_child("create_game");
00951 create_game["name"] = params.name;
00952 if(params.password.empty() == false) {
00953 create_game["password"] = params.password;
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966 network::send_data(response, 0, true);
00967
00968
00969 users_.push_back(connected_user(preferences::login(), CNTR_LOCAL, 0));
00970 update_user_combos();
00971
00972 int side_choice = -1;
00973 for(side_list::const_iterator s = sides_.begin(); s != sides_.end(); ++s) {
00974 if (s->allow_player()) {
00975 if (side_choice == -1)
00976 side_choice = s - sides_.begin();
00977 if(s->get_save_id() == preferences::login()) {
00978 side_choice = s - sides_.begin();
00979 break;
00980 }
00981 }
00982 }
00983
00984 if (side_choice != -1)
00985 {
00986 sides_[side_choice].set_id(preferences::login());
00987 }
00988
00989
00990 update_level();
00991 update_playerlist_state(true);
00992
00993
00994 network::send_data(level_, 0, true);
00995 }
00996
00997 void connect::process_event()
00998 {
00999 bool changed = false;
01000
01001 for(size_t n = 0; n != sides_.size(); ++n) {
01002 sides_[n].process_event();
01003 if (sides_[n].changed())
01004 changed = true;
01005 }
01006
01007 if (cancel_.pressed()) {
01008 if(network::nconnections() > 0) {
01009 config cfg;
01010 cfg.add_child("leave_game");
01011 network::send_data(cfg, 0, true);
01012 }
01013
01014 set_result(QUIT);
01015 return;
01016 }
01017
01018 if (launch_.pressed()) {
01019 if (!sides_available())
01020 set_result(mp::ui::PLAY);
01021 }
01022
01023
01024
01025 if (changed) {
01026 update_playerlist_state();
01027 update_and_send_diff();
01028 }
01029 }
01030
01031 const game_state& connect::get_state()
01032 {
01033 return state_;
01034 }
01035
01036 void connect::start_game()
01037 {
01038
01039 for (side_list::iterator itor = sides_.begin(); itor != sides_.end();
01040 ++itor) {
01041
01042 itor->resolve_random();
01043 }
01044
01045 config lock;
01046 lock.add_child("stop_updates");
01047 network::send_data(lock, 0, true);
01048 update_and_send_diff(true);
01049
01050
01051
01052 level_to_gamestate(level_, state_, params_.saved_game);
01053
01054
01055 const config* const era_cfg = level_.child("era");
01056 if (era_cfg != NULL && level_["savegame"] != "yes") {
01057 game_events::add_events(era_cfg->get_children("event"),"era_events");
01058 }
01059
01060 network::send_data(config("start_game"), 0, true);
01061 }
01062
01063 void connect::hide_children(bool hide)
01064 {
01065 ui::hide_children(hide);
01066
01067 waiting_label_.hide(hide);
01068
01069 scroll_pane_.hide(hide);
01070 for (side_list::iterator itor = sides_.begin(); itor != sides_.end(); ++itor) {
01071 itor->hide_ai_algorithm_combo(hide);
01072 }
01073 faction_title_label_.hide(hide);
01074 team_title_label_.hide(hide);
01075 colour_title_label_.hide(hide);
01076 if (!params_.saved_game) {
01077 gold_title_label_.hide(hide);
01078 income_title_label_.hide(hide);
01079 }
01080
01081 launch_.hide(hide);
01082 cancel_.hide(hide);
01083 }
01084
01085 void connect::process_network_data(const config& data, const network::connection sock)
01086 {
01087 ui::process_network_data(data, sock);
01088
01089 if(data.child("leave_game")) {
01090 set_result(QUIT);
01091 return;
01092 }
01093
01094 if (!data["side_drop"].empty()) {
01095 const int side_drop = lexical_cast_default<int>(data["side_drop"], 0) - 1;
01096 if(side_drop >= 0 && side_drop < int(sides_.size())) {
01097 connected_user_list::iterator player = find_player(sides_[side_drop].get_id());
01098 sides_[side_drop].reset(sides_[side_drop].get_controller());
01099 if (player != users_.end()) {
01100 users_.erase(player);
01101 update_user_combos();
01102 }
01103 update_and_send_diff();
01104 return;
01105 }
01106 }
01107
01108 if (!data["side"].empty()) {
01109 int side_taken = lexical_cast_default<int>(data["side"], 0) - 1;
01110
01111
01112 const std::string name = data["name"];
01113 if(name.empty()) {
01114 config response;
01115 response.values["failed"] = "yes";
01116 network::send_data(response, sock, true);
01117 ERR_CF << "ERROR: No username provided with the side.\n";
01118 return;
01119 }
01120
01121 connected_user_list::iterator player = find_player(name);
01122 if(player != users_.end()) {
01123
01124
01125 if(find_player_side(name) != -1) {
01126 config response;
01127 response.values["failed"] = "yes";
01128 response["message"] = "The nick '" + name + "' is already in use.";
01129 network::send_data(response, sock, true);
01130 return;
01131 } else {
01132 users_.erase(player);
01133 config observer_quit;
01134 observer_quit.add_child("observer_quit").values["name"] = name;
01135 network::send_data(observer_quit, 0, true);
01136 update_user_combos();
01137 }
01138 }
01139
01140
01141 if(side_taken >= 0 && side_taken < int(sides_.size())) {
01142 if(!sides_[side_taken].available()) {
01143
01144
01145 side_list::const_iterator itor;
01146 side_taken = 0;
01147 for (itor = sides_.begin(); itor != sides_.end();
01148 ++itor, ++side_taken) {
01149 if(itor->available())
01150 break;
01151 }
01152
01153 if(itor == sides_.end()) {
01154 config response;
01155 response.values["failed"] = "yes";
01156 network::send_data(response, sock, true);
01157 config kick;
01158 kick["username"] = data["name"];
01159 config res;
01160 res.add_child("kick", kick);
01161 network::send_data(res, 0, true);
01162 update_user_combos();
01163 update_and_send_diff();
01164 ERR_CF << "ERROR: Couldn't assign a side to '" << name << "'\n";
01165 return;
01166 }
01167 }
01168
01169 LOG_CF << "client has taken a valid position\n";
01170
01171
01172 users_.push_back(connected_user(name, CNTR_NETWORK, sock));
01173 update_user_combos();
01174
01175
01176 sides_[side_taken].import_network_user(data);
01177 update_playerlist_state(false);
01178 update_and_send_diff();
01179
01180 LOG_NW << "sent player data\n";
01181
01182 } else {
01183 ERR_CF << "tried to take illegal side: " << side_taken << '\n';
01184 config response;
01185 response.values["failed"] = "yes";
01186 network::send_data(response, sock, true);
01187 }
01188 }
01189
01190 const config* change_faction = data.child("change_faction");
01191 if(change_faction != NULL) {
01192 int side_taken = find_player_side(change_faction->get_attribute("name"));
01193 if(side_taken != -1) {
01194 sides_[side_taken].import_network_user(*change_faction);
01195 update_playerlist_state();
01196 update_and_send_diff();
01197 }
01198 }
01199
01200 if(data.child("observer") != NULL) {
01201 const t_string& observer_name = data.child("observer")->get_attribute("name");
01202 if(!observer_name.empty()) {
01203 connected_user_list::iterator player = find_player(observer_name);
01204 if(player == users_.end()) {
01205 users_.push_back(connected_user(observer_name, CNTR_NETWORK, sock));
01206 update_user_combos();
01207 update_playerlist_state();
01208 update_and_send_diff();
01209 }
01210 }
01211 }
01212 if(data.child("observer_quit") != NULL) {
01213 const t_string& observer_name = data.child("observer_quit")->get_attribute("name");
01214 if(!observer_name.empty()) {
01215 connected_user_list::iterator player = find_player(observer_name);
01216 if(player != users_.end() && find_player_side(observer_name) == -1) {
01217 users_.erase(player);
01218 update_user_combos();
01219 update_playerlist_state();
01220 update_and_send_diff();
01221 }
01222 }
01223 }
01224 }
01225
01226 void connect::process_network_error(network::error& error)
01227 {
01228
01229
01230
01231
01232 if(!error.socket || !network::is_server()) {
01233 error.disconnect();
01234 throw network::error(error.message);
01235 }
01236
01237 bool changes = false;
01238
01239
01240 connected_user_list::iterator user;
01241 for(user = users_.begin(); user != users_.end(); ++user) {
01242 if(user->connection == error.socket) {
01243 changes = true;
01244
01245 int i = find_player_side(user->name);
01246 if (i != -1)
01247 sides_[i].reset(default_controller_);
01248
01249 break;
01250 }
01251 }
01252 if(user != users_.end()) {
01253 users_.erase(user);
01254 update_user_combos();
01255 }
01256
01257
01258 error.disconnect();
01259
01260
01261
01262 if(changes) {
01263 update_and_send_diff();
01264 update_playerlist_state();
01265 }
01266 }
01267
01268 bool connect::accept_connections()
01269 {
01270 if (sides_available())
01271 return true;
01272 return false;
01273 }
01274
01275 void connect::process_network_connection(const network::connection sock)
01276 {
01277 ui::process_network_connection(sock);
01278
01279 network::send_data(config("join_game"), 0, true);
01280
01281 network::send_data(level_, sock, true);
01282 }
01283
01284 void connect::layout_children(const SDL_Rect& rect)
01285 {
01286 ui::layout_children(rect);
01287
01288 SDL_Rect ca = client_area();
01289
01290 gui::button* left_button = &launch_;
01291 gui::button* right_button = &cancel_;
01292 #ifdef OK_BUTTON_ON_RIGHT
01293 std::swap(left_button,right_button);
01294 #endif
01295 size_t left = ca.x;
01296 size_t right = ca.x + ca.w;
01297 size_t top = ca.y;
01298 size_t bottom = ca.y + ca.h;
01299
01300
01301 right_button->set_location(right - right_button->width(),
01302 bottom - right_button->height());
01303 left_button->set_location(right - right_button->width() - left_button->width() - gui::ButtonHPadding,
01304 bottom - left_button->height());
01305
01306 waiting_label_.set_location(left + 8, bottom-left_button->height() + 4);
01307 type_title_label_.set_location(left+30, top+35);
01308 faction_title_label_.set_location((left+145), top+35);
01309 team_title_label_.set_location((left+260), top+35);
01310 colour_title_label_.set_location((left+375), top+35);
01311 gold_title_label_.set_location((left+493), top+35);
01312 income_title_label_.set_location((left+560), top+35);
01313
01314 SDL_Rect scroll_pane_rect;
01315 scroll_pane_rect.x = ca.x;
01316 scroll_pane_rect.y = ca.y + 50;
01317 scroll_pane_rect.w = ca.w;
01318 scroll_pane_rect.h = launch_.location().y - scroll_pane_rect.y - gui::ButtonVPadding;
01319
01320 scroll_pane_.set_location(scroll_pane_rect);
01321 }
01322
01323 void connect::lists_init()
01324 {
01325
01326 player_types_.push_back(_("Network Player"));
01327 player_types_.push_back(_("Local Player"));
01328 player_types_.push_back(_("Computer Player"));
01329 player_types_.push_back(_("Empty"));
01330
01331 for(std::vector<config*>::const_iterator faction = era_sides_.begin();
01332 faction != era_sides_.end();
01333 ++faction) {
01334 player_factions_.push_back((**faction)["name"]);
01335 }
01336
01337
01338 ai_algorithms_ = get_available_ais();
01339
01340
01341 const config::child_itors sides = current_config()->child_range("side");
01342
01343
01344 config::child_iterator sd;
01345 if(params_.use_map_settings) {
01346 for(sd = sides.first; sd != sides.second; ++sd) {
01347 const int side_num = sd - sides.first + 1;
01348 t_string& team_name = (**sd)["team_name"];
01349 t_string& user_team_name = (**sd)["user_team_name"];
01350
01351 if(team_name.empty())
01352 team_name = lexical_cast<std::string>(side_num);
01353
01354 if(user_team_name.empty())
01355 {
01356 user_team_name = team_name;
01357 }
01358
01359 std::vector<std::string>::const_iterator itor = std::find(team_names_.begin(),
01360 team_names_.end(), team_name);
01361 if(itor == team_names_.end()) {
01362 team_names_.push_back(team_name);
01363 user_team_names_.push_back(user_team_name);
01364 player_teams_.push_back(user_team_name.str());
01365 }
01366 }
01367 } else {
01368 std::vector<std::string> map_team_names;
01369 for(sd = sides.first; sd != sides.second; ++sd) {
01370 const std::string side_num = lexical_cast<std::string>(sd - sides.first + 1);
01371 t_string& team_name = (**sd)["team_name"];
01372
01373 if(team_name.empty())
01374 team_name = side_num;
01375
01376 std::vector<std::string>::const_iterator itor = std::find(map_team_names.begin(),
01377 map_team_names.end(), team_name);
01378 if(itor == map_team_names.end()) {
01379 map_team_names.push_back(team_name);
01380 team_name = lexical_cast<std::string>(map_team_names.size());
01381 } else {
01382 team_name = lexical_cast<std::string>(itor - map_team_names.begin() + 1);
01383 }
01384
01385 team_names_.push_back(side_num);
01386 user_team_names_.push_back(team_prefix_ + side_num);
01387 player_teams_.push_back(team_prefix_ + side_num);
01388 }
01389 }
01390
01391
01392 for(int i = 0; i < gamemap::MAX_PLAYERS; ++i) {
01393 player_colours_.push_back(get_colour_string(i));
01394 }
01395
01396
01397 sides_.reserve(sides.second - sides.first);
01398 int index = 0;
01399 for(sd = sides.first; sd != sides.second; ++sd, ++index) {
01400 sides_.push_back(side(*this, **sd, index));
01401 }
01402 int offset=0;
01403
01404 for(side_list::iterator s = sides_.begin(); s != sides_.end(); ++s) {
01405 const int side_num = s - sides_.begin();
01406 const int spos = 60 * (side_num-offset);
01407 if(!s->allow_player()) {
01408 offset++;
01409 continue;
01410 }
01411
01412 s->add_widgets_to_scrollpane(scroll_pane_, spos);
01413 }
01414 }
01415
01416
01417 void connect::load_game()
01418 {
01419 if(params_.saved_game) {
01420 bool show_replay = false;
01421
01422 const std::string game = dialogs::load_game_dialog(disp(),
01423 game_config(), &show_replay,
01424 NULL);
01425
01426 if(game.empty()) {
01427 set_result(CREATE);
01428 return;
01429 }
01430
01431 std::string error_log;
01432 {
01433 cursor::setter cur(cursor::WAIT);
01434 ::load_game(game, state_, &error_log);
01435 }
01436 if(!error_log.empty()) {
01437 gui::show_error_message(disp(),
01438 _("The file you have tried to load is corrupt: '") +
01439 error_log);
01440 set_result(CREATE);
01441 return;
01442 }
01443
01444 if(state_.campaign_type != "multiplayer") {
01445
01446 gui::message_dialog dlg(disp(), "", _("This is not a multiplayer save"));
01447 dlg.show();
01448 set_result(CREATE);
01449 return;
01450 }
01451
01452 if(state_.version != game_config::version) {
01453
01454
01455 if(state_.version < game_config::min_savegame_version &&
01456 game_config::test_version.full != state_.version &&
01457 game_config::test_version.full != game_config::version) {
01458
01459
01460 gui::message_dialog dlg2(disp(), "", _("This save is from a version too old to be loaded."));
01461 dlg2.show();
01462 set_result(CREATE);
01463 return;
01464 }
01465
01466 const int res = gui::dialog(disp(), "",
01467 _("This save is from a different version of the game. Do you want to try to load it?"),
01468 gui::YES_NO).show();
01469 if(res == 1) {
01470 set_result(CREATE);
01471 return;
01472 }
01473 }
01474
01475 level_["savegame"] = "yes";
01476
01477
01478 const config& start_data = !state_.snapshot.empty() ? state_.snapshot : state_.starting_pos;
01479 level_["map_data"] = start_data["map_data"];
01480 level_["id"] = start_data["id"];
01481 level_["name"] = start_data["name"];
01482
01483 level_["turn"] = start_data["turn_at"];
01484 level_["turn_at"] = start_data["turn_at"];
01485 level_["turns"] = start_data["turns"];
01486 level_["mp_use_map_settings"] = start_data["mp_use_map_settings"];
01487 level_["mp_village_gold"] = start_data["mp_village_gold"];
01488 level_["mp_fog"] = start_data["mp_fog"];
01489 level_["mp_shroud"] = start_data["mp_shroud"];
01490 level_["mp_countdown"] = start_data["mp_countdown"];
01491 level_["mp_countdown_init_time"] = start_data["mp_countdown_init_time"];
01492 level_["mp_countdown_turn_bonus"] = start_data["mp_countdown_turn_bonus"];
01493 level_["mp_countdown_action_bonus"] = start_data["mp_countdown_action_bonus"];
01494 level_["experience_modifier"] = start_data["experience_modifier"];
01495 level_["observer"] = start_data["observer"];
01496 level_.add_child("snapshot") = start_data;
01497 level_["random_seed"] = start_data["random_seed"];
01498 level_["random_calls"] = start_data["random_calls"];
01499
01500
01501
01502 level_.add_child("replay") = state_.replay_data;
01503 if(!state_.starting_pos.empty())
01504 level_.add_child("replay_start") = state_.starting_pos;
01505 level_.add_child("statistics") = statistics::write_stats();
01506
01507 } else {
01508 level_["savegame"] = "no";
01509 level_ = params_.scenario_data;
01510
01511 level_["hash"] = level_.hash();
01512 level_["turns"] = lexical_cast_default<std::string>(params_.num_turns, "20");
01513 level_["mp_countdown"] = params_.mp_countdown ? "yes" : "no";
01514 level_["mp_countdown_init_time"] = lexical_cast_default<std::string>(params_.mp_countdown_init_time, "270");
01515 level_["mp_countdown_turn_bonus"] = lexical_cast_default<std::string>(params_.mp_countdown_turn_bonus, "35");
01516 level_["mp_countdown_reservoir_time"] = lexical_cast_default<std::string>(params_.mp_countdown_reservoir_time, "330");
01517 level_["mp_countdown_action_bonus"] = lexical_cast_default<std::string>(params_.mp_countdown_action_bonus, "13");
01518
01519 if (params_.random_start_time)
01520 {
01521 if (!gamestatus::is_start_ToD(level_["random_start_time"]))
01522 {
01523 level_["random_start_time"] = "yes";
01524 }
01525 }
01526 else
01527 {
01528 level_["random_start_time"] = "no";
01529 }
01530
01531 level_["scenario"] = params_.name;
01532 level_["experience_modifier"] = lexical_cast<std::string>(params_.xp_modifier);
01533 level_["random_seed"] = lexical_cast<std::string>(state_.rng().get_random_seed());
01534 level_["mp_village_gold"] = lexical_cast<std::string>(params_.village_gold);
01535 level_["mp_fog"] = params_.fog_game ? "yes" : "no";
01536 level_["mp_shroud"] = params_.shroud_game ? "yes" : "no";
01537 level_["mp_use_map_settings"] = params_.use_map_settings ? "yes" : "no";
01538 }
01539
01540
01541 append_to_title(" - " + level_["name"]);
01542
01543
01544 std::string era;
01545 if (params_.saved_game
01546 && level_.child("snapshot")->child("era"))
01547 {
01548 era = level_.child("snapshot")->child("era")->get_attribute("id");
01549 }
01550 else
01551 {
01552 era = params_.era;
01553 }
01554
01555
01556 const config* const era_cfg = game_config().find_child("era", "id", era);
01557 if(!era_cfg) {
01558 if (!params_.saved_game)
01559 {
01560 utils::string_map i18n_symbols;
01561 i18n_symbols["era"] = era;
01562 throw config::error(vgettext("Cannot find era $era", i18n_symbols));
01563 }
01564
01565 WRN_CF << "Missing era in MP load game " << era << "\n";
01566
01567 }
01568 if (era_cfg)
01569 {
01570 era_sides_ = era_cfg->get_children("multiplayer_side");
01571 level_.add_child("era", *era_cfg);
01572 }
01573
01574 gold_title_label_.hide(params_.saved_game);
01575 income_title_label_.hide(params_.saved_game);
01576
01577
01578 level_["version"] = game_config::version;
01579
01580 level_["observer"] = params_.allow_observers ? "yes" : "no";
01581
01582 if(level_["objectives"].empty()) {
01583 level_["objectives"] = t_string(N_("Victory:\n\
01584 @Defeat enemy leader(s)"), "wesnoth");
01585 }
01586 }
01587
01588 config* connect::current_config(){
01589 config* cfg_level = NULL;
01590
01591 if (level_.child("snapshot") != NULL){
01592
01593 cfg_level = level_.child("snapshot");
01594 }
01595 else{
01596
01597 cfg_level = &level_;
01598 }
01599
01600 return cfg_level;
01601 }
01602
01603 void connect::update_level()
01604 {
01605
01606 level_.clear_children("side");
01607 for(side_list::const_iterator itor = sides_.begin(); itor != sides_.end();
01608 ++itor) {
01609
01610 level_.add_child("side", itor->get_config());
01611 }
01612 }
01613
01614 void connect::update_and_send_diff(bool update_time_of_day)
01615 {
01616 config old_level = level_;
01617 update_level();
01618 if (update_time_of_day)
01619 {
01620
01621 gamestatus game_status(level_,atoi(level_["turns"].c_str()),&state_);
01622 }
01623
01624 config diff = level_.get_diff(old_level);
01625 if (!diff.empty()) {
01626 config scenario_diff;
01627 scenario_diff.add_child("scenario_diff", diff);
01628 network::send_data(scenario_diff, 0, true);
01629 }
01630 }
01631
01632 bool connect::sides_available()
01633 {
01634 for(side_list::const_iterator itor = sides_.begin(); itor != sides_.end(); ++itor) {
01635 if (itor->available())
01636 return true;
01637 }
01638 return false;
01639 }
01640
01641 void connect::update_playerlist_state(bool silent)
01642 {
01643 waiting_label_.set_text(sides_available() ? _("Waiting for players to join...") : "");
01644 launch_.enable(!sides_available());
01645
01646
01647
01648 if (gamelist().child("user") != NULL) {
01649 ui::gamelist_updated(silent);
01650 } else {
01651
01652 std::vector<std::string> playerlist;
01653 for(connected_user_list::const_iterator itor = users_.begin();
01654 itor != users_.end();
01655 ++itor) {
01656 playerlist.push_back(itor->name);
01657 }
01658 set_user_list(playerlist, silent);
01659 set_user_menu_items(playerlist);
01660 }
01661 }
01662
01663 connect::connected_user_list::iterator connect::find_player(const std::string& id)
01664 {
01665 connected_user_list::iterator itor;
01666 for (itor = users_.begin(); itor != users_.end(); ++itor) {
01667 if (itor->name == id)
01668 break;
01669 }
01670 return itor;
01671 }
01672
01673 int connect::find_player_side(const std::string& id) const
01674 {
01675 side_list::const_iterator itor;
01676 for (itor = sides_.begin(); itor != sides_.end(); ++itor) {
01677 if (itor->get_id() == id)
01678 break;
01679 }
01680
01681 if (itor == sides_.end())
01682 return -1;
01683
01684 return itor - sides_.begin();
01685 }
01686
01687 void connect::update_user_combos()
01688 {
01689 for (side_list::iterator itor = sides_.begin();
01690 itor != sides_.end(); ++itor) {
01691 itor->update_user_list();
01692 }
01693 }
01694
01695 void connect::kick_player(const std::string& name)
01696 {
01697 connected_user_list::iterator player = find_player(name);
01698 if(player == users_.end())
01699 return;
01700
01701 if(player->controller != CNTR_NETWORK)
01702 return;
01703
01704
01705
01706 if(network::is_server()) {
01707 network::disconnect(player->connection);
01708 } else {
01709 config kick;
01710 kick["username"] = name;
01711 config res;
01712 res.add_child("kick", kick);
01713 network::send_data(res, 0, true);
01714 }
01715
01716 int side = find_player_side(name);
01717 if (side != -1) {
01718 assert(size_t(side) < sides_.size());
01719 sides_[side].reset(sides_[side].get_controller());
01720 }
01721 users_.erase(player);
01722 update_user_combos();
01723 }
01724
01725 }
01726