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