00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "../global.hpp"
00017
00018 #include "../filesystem.hpp"
00019 #include "../game_config.hpp"
00020 #include "../log.hpp"
00021 #include "../map.hpp"
00022
00023 #include "game.hpp"
00024 #include "player_network.hpp"
00025 #include "serialization/string_utils.hpp"
00026 #include "util.hpp"
00027
00028 #include <boost/bind.hpp>
00029
00030 static lg::log_domain log_server("server");
00031 #define ERR_GAME LOG_STREAM(err, log_server)
00032 #define WRN_GAME LOG_STREAM(warn, log_server)
00033 #define LOG_GAME LOG_STREAM(info, log_server)
00034 #define DBG_GAME LOG_STREAM(debug, log_server)
00035 static lg::log_domain log_config("config");
00036 #define WRN_CONFIG LOG_STREAM(warn, log_config)
00037
00038 namespace wesnothd {
00039 int game::id_num = 1;
00040
00041 void game::missing_user(network::connection socket, const std::string& func) const
00042 {
00043 WRN_GAME << func << "(): Could not find user (socket:\t" << socket
00044 << ") in player_info_ in game:\t\"" << name_ << "\" (" << id_ << ")\n";
00045 }
00046
00047 game::game(player_map& players, const network::connection host,
00048 const std::string& name, bool save_replays,
00049 const std::string& replay_save_path) :
00050 player_info_(&players),
00051 id_(id_num++),
00052 name_(name),
00053 password_(),
00054 owner_(host),
00055 players_(),
00056 observers_(),
00057 muted_observers_(),
00058 sides_(gamemap::MAX_PLAYERS),
00059 side_controllers_(gamemap::MAX_PLAYERS),
00060 nsides_(0),
00061 started_(false),
00062 level_(),
00063 history_(),
00064 description_(NULL),
00065 end_turn_(0),
00066 all_observers_muted_(false),
00067 bans_(),
00068 termination_(),
00069 save_replays_(save_replays),
00070 replay_save_path_(replay_save_path),
00071 global_wait_side_(0)
00072 {
00073 assert(owner_);
00074 players_.push_back(owner_);
00075 const player_map::iterator pl = player_info_->find(owner_);
00076 if (pl == player_info_->end()) {
00077 missing_user(owner_, __func__);
00078 return;
00079 }
00080
00081 pl->second.mark_available(id_, name_);
00082 pl->second.set_status(player::PLAYING);
00083 }
00084
00085 game::~game()
00086 {
00087 save_replay();
00088
00089 user_vector users = all_game_users();
00090 for (user_vector::const_iterator u = users.begin(); u != users.end(); ++u) {
00091 remove_player(*u, false, true);
00092 }
00093 clear_history();
00094 }
00095
00096 bool game::allow_observers() const {
00097 return level_["observer"].to_bool(true);
00098 }
00099
00100 bool game::is_observer(const network::connection player) const {
00101 return std::find(observers_.begin(),observers_.end(),player) != observers_.end();
00102 }
00103
00104 bool game::is_muted_observer(const network::connection player) const {
00105 if (is_observer(player)) {
00106 if (all_observers_muted_) return true;
00107 } else {
00108 return false;
00109 }
00110 return std::find(muted_observers_.begin(), muted_observers_.end(), player)
00111 != muted_observers_.end();
00112 }
00113
00114 bool game::is_player(const network::connection player) const {
00115 return std::find(players_.begin(),players_.end(),player) != players_.end();
00116 }
00117
00118 namespace {
00119 std::string describe_turns(int turn, const simple_wml::string_span& num_turns)
00120 {
00121 char buf[50];
00122 snprintf(buf,sizeof(buf),"%d/",int(turn));
00123
00124 if(num_turns == "-1") {
00125 return buf + std::string("-");
00126 } else {
00127 return buf + std::string(num_turns.begin(), num_turns.end());
00128 }
00129 }
00130
00131 }
00132
00133 std::string game::username(const player_map::const_iterator pl) const
00134 {
00135 if (pl != player_info_->end()) {
00136 return pl->second.name();
00137 }
00138
00139 return "(unknown)";
00140 }
00141
00142 std::string game::list_users(user_vector users, const std::string& func) const
00143 {
00144 std::string list;
00145
00146 for (user_vector::const_iterator user = users.begin(); user != users.end(); ++user) {
00147 const player_map::const_iterator pl = player_info_->find(*user);
00148 if (pl != player_info_->end()) {
00149 if (!list.empty()) list += ", ";
00150 list += pl->second.name();
00151 } else missing_user(*user, func);
00152 }
00153
00154 return list;
00155 }
00156
00157 void game::start_game(const player_map::const_iterator starter) {
00158
00159 const bool advance = started_;
00160 started_ = true;
00161
00162 const simple_wml::node& s = level_.root();
00163 const bool save = s["savegame"].to_bool();
00164 LOG_GAME << network::ip_address(starter->first) << "\t"
00165 << starter->second.name() << "\t" << (advance ? "advanced" : "started")
00166 << (save ? " reloaded" : "") << " game:\t\"" << name_ << "\" (" << id_
00167 << ") with: " << list_users(players_, __func__) << ". Settings: map: " << s["id"]
00168 << "\tera: " << (s.child("era") ? (*s.child("era"))["id"] : "")
00169 << "\tXP: " << s["experience_modifier"]
00170 << "\tGPV: " << s["mp_village_gold"]
00171 << "\tfog: " << s["mp_fog"]
00172 << "\tshroud: " << s["mp_shroud"]
00173 << "\tobservers: " << s["observer"]
00174 << "\tshuffle: " << s["shuffle_sides"]
00175 << "\ttimer: " << s["mp_countdown"]
00176 << (s["mp_countdown"].to_bool() ?
00177 "\treservoir time: " + s["mp_countdown_reservoir_time"].to_string() +
00178 "\tinit time: " + s["mp_countdown_init_time"].to_string() +
00179 "\taction bonus: " + s["mp_countdown_action_bonus"].to_string() +
00180 "\tturn bonus: " + s["mp_countdown_turn_bonus"].to_string() : "")
00181 << "\n";
00182
00183 update_side_data();
00184
00185 nsides_ = 0;
00186
00187
00188
00189 const simple_wml::node::child_list& sides = level_.root().children("side");
00190 for(simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
00191 nsides_++;
00192 if ((**s)["controller"] != "null") {
00193 int side_num = (**s)["side"].to_int() - 1;
00194 if (sides_[side_num] == 0) {
00195 std::stringstream msg;
00196 msg << "Side " << side_num + 1 << " has no controller but should! The host needs to assign control for the game to proceed past that side's turn.";
00197 LOG_GAME << msg.str() << " (game id: " << id_ << ")\n";
00198 send_and_record_server_message(msg.str());
00199 }
00200 (*s)->set_attr("controller", "human");
00201 }
00202 }
00203
00204 DBG_GAME << "Number of sides: " << nsides_ << "\n";
00205 int turn = 1;
00206 int side = 0;
00207
00208 if (const simple_wml::node* snapshot = s.child("snapshot")) {
00209 turn = lexical_cast_default<int>((*snapshot)["turn_at"], 1);
00210 side = lexical_cast_default<int>((*snapshot)["playing_team"], 0);
00211 LOG_GAME << "Reload from turn: " << turn
00212 << ". Current side is: " << side + 1 << ".\n";
00213 }
00214 end_turn_ = (turn - 1) * nsides_ + side - 1;
00215 end_turn();
00216 clear_history();
00217 if (advance) {
00218
00219
00220 static simple_wml::document notify_next_scenario("[notify_next_scenario]\n[/notify_next_scenario]\n", simple_wml::INIT_COMPRESSED);
00221 send_data(notify_next_scenario, starter->first);
00222 }
00223
00224 send_observerjoins();
00225 }
00226
00227 bool game::send_taken_side(simple_wml::document& cfg, const simple_wml::node::child_list::const_iterator side) const
00228 {
00229 const size_t side_num = (**side)["side"].to_int();
00230 if (side_num < 1 || side_num > gamemap::MAX_PLAYERS) return false;
00231 if (sides_[side_num - 1] != 0) return false;
00232
00233 cfg.root().set_attr_dup("side", (**side)["side"]);
00234
00235
00236 return wesnothd::send_to_one(cfg, owner_);
00237 }
00238
00239 bool game::take_side(const player_map::const_iterator user)
00240 {
00241 DBG_GAME << "take_side...\n";
00242
00243 if (started_) return false;
00244
00245 simple_wml::document cfg;
00246 cfg.root().set_attr_dup("name", user->second.name().c_str());
00247 cfg.root().set_attr("faction", "random");
00248 cfg.root().set_attr("leader", "random");
00249 cfg.root().set_attr("gender", "random");
00250
00251
00252 const simple_wml::node::child_list& sides = level_.root().children("side");
00253 for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
00254 if(((**side)["controller"] == "network" || (**side)["controller"] == "reserved")
00255 && ((**side)["save_id"] == user->second.name().c_str()
00256 || (**side)["current_player"] == user->second.name().c_str()))
00257 {
00258 if (send_taken_side(cfg, side)) return true;
00259 }
00260 }
00261
00262 for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
00263 if((**side)["controller"] == "network") {
00264 if (send_taken_side(cfg, side)) return true;
00265 }
00266 }
00267 DBG_GAME << "take_side: there are no more sides available\n";
00268
00269 return false;
00270 }
00271
00272 void game::update_side_data() {
00273 DBG_GAME << "update_side_data...\n";
00274 DBG_GAME << debug_player_info();
00275
00276 const user_vector users = all_game_users();
00277
00278 side_controllers_.clear();
00279 side_controllers_.resize(gamemap::MAX_PLAYERS);
00280 sides_.clear();
00281 sides_.resize(gamemap::MAX_PLAYERS);
00282 players_.clear();
00283 observers_.clear();
00284
00285 const simple_wml::node::child_list& level_sides = level_.root().children("side");
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 for (user_vector::const_iterator user = users.begin(); user != users.end(); ++user) {
00296 player_map::iterator info = player_info_->find(*user);
00297 if (info == player_info_->end()) {
00298 missing_user(*user, __func__);
00299 continue;
00300 }
00301
00302 bool side_found = false;
00303 for (simple_wml::node::child_list::const_iterator side = level_sides.begin();
00304 side != level_sides.end(); ++side)
00305 {
00306 int side_num = (**side)["side"].to_int() - 1;
00307 if (side_num < 0 || side_num >= gamemap::MAX_PLAYERS
00308 || sides_[side_num] != 0) continue;
00309
00310 if ((**side)["controller"] == "network") {
00311 if ((**side)["current_player"] == info->second.name().c_str()) {
00312 side_controllers_[side_num] = "human";
00313 sides_[side_num] = *user;
00314 side_found = true;
00315 }
00316 } else if (*user == owner_
00317 && ((**side)["controller"] == "ai" || (**side)["controller"] == "human")) {
00318 side_controllers_[side_num] = (**side)["controller"].to_string();
00319 sides_[side_num] = owner_;
00320 side_found = true;
00321 } else {
00322
00323 side_controllers_[side_num] = (**side)["controller"].to_string();
00324 }
00325 }
00326 if (side_found) {
00327 players_.push_back(*user);
00328 info->second.set_status(player::PLAYING);
00329 } else {
00330 observers_.push_back(*user);
00331 info->second.set_status(player::OBSERVING);
00332 }
00333 }
00334 DBG_GAME << debug_player_info();
00335 }
00336
00337 void game::transfer_side_control(const network::connection sock, const simple_wml::node& cfg) {
00338 DBG_GAME << "transfer_side_control...\n";
00339 if (!is_player(sock) && sock != owner_) {
00340 send_server_message("You cannot change controllers: not a player.", sock);
00341 return;
00342 }
00343
00344
00345 const unsigned int side_num = cfg["side"].to_int();
00346 if(side_num < 1 || side_num > gamemap::MAX_PLAYERS) {
00347 std::ostringstream msg;
00348 msg << "The side number has to be between 1 and "
00349 << gamemap::MAX_PLAYERS << ".";
00350 send_server_message(msg.str(), sock);
00351 return;
00352 }
00353
00354 if (side_num > level_.root().children("side").size()) {
00355 send_server_message("Invalid side number.", sock);
00356 return;
00357 }
00358
00359 const simple_wml::string_span& newplayer_name = cfg["player"];
00360 const network::connection old_player = sides_[side_num - 1];
00361 const player_map::iterator oldplayer = player_info_->find(old_player);
00362 if (oldplayer == player_info_->end()) missing_user(old_player, __func__);
00363 const std::string old_player_name = username(oldplayer);
00364
00365
00366 if (newplayer_name.empty()) {
00367 if (sock != old_player) {
00368 if (cfg["controller"].empty()) {
00369 send_server_message("No player name or controller type given.", sock);
00370 } else {
00371 send_server_message("You can only (un)droid your own sides!", sock);
00372 }
00373 return;
00374 } else if (cfg["controller"] != "human_ai" && cfg["controller"] != "human") {
00375 std::stringstream msg;
00376 msg << "Wrong controller type received: '" << cfg["controller"] << "'";
00377 DBG_GAME << msg.str() << "\n";
00378 send_server_message(msg.str(), sock);
00379 return;
00380 }
00381 change_controller(side_num - 1, old_player, old_player_name, false, cfg["controller"].to_string());
00382 return;
00383 }
00384
00385
00386 if (!(sock == old_player || sock == owner_)) {
00387 std::stringstream msg;
00388 msg << "You can't give away side " << side_num << ". It's controlled by '"
00389 << old_player_name << "' not you.";
00390 DBG_GAME << msg.str() << "\n";
00391 send_server_message(msg.str(), sock);
00392 return;
00393 }
00394
00395 player_map::iterator newplayer = find_user(newplayer_name);
00396
00397
00398 if (newplayer == player_info_->end() || !is_member(newplayer->first)) {
00399 send_server_message(newplayer_name.to_string() + " is not in this game", sock);
00400 return;
00401 }
00402
00403 if (newplayer->first == old_player) {
00404 std::stringstream msg;
00405 msg << "That's already " << newplayer_name << "'s side, silly.";
00406 send_server_message(msg.str(), sock);
00407 return;
00408 }
00409 sides_[side_num - 1] = 0;
00410
00411 if (std::find(sides_.begin(), sides_.end(), old_player) == sides_.end()
00412 && is_player(old_player)) {
00413 observers_.push_back(old_player);
00414 oldplayer->second.set_status(player::OBSERVING);
00415 players_.erase(std::remove(players_.begin(), players_.end(), old_player), players_.end());
00416
00417 send_and_record_server_message(old_player_name + " becomes an observer.");
00418
00419 simple_wml::document observer_join;
00420 observer_join.root().add_child("observer").set_attr_dup("name", old_player_name.c_str());
00421 send_data(observer_join, old_player);
00422 }
00423 change_controller(side_num - 1, newplayer->first, newplayer->second.name(), false);
00424
00425
00426 if (is_observer(newplayer->first)) {
00427 players_.push_back(newplayer->first);
00428 newplayer->second.set_status(player::PLAYING);
00429 observers_.erase(std::remove(observers_.begin(), observers_.end(), newplayer->first), observers_.end());
00430
00431 send_observerquit(newplayer);
00432 }
00433 }
00434
00435 void game::change_controller(const size_t side_num,
00436 const network::connection sock,
00437 const std::string& player_name,
00438 const bool player_left,
00439 const std::string& controller)
00440 {
00441 DBG_GAME << __func__ << "...\n";
00442
00443 const std::string& side = lexical_cast<std::string, size_t>(side_num + 1);
00444 sides_[side_num] = sock;
00445
00446 if (player_left && side_controllers_[side_num] == "ai") {
00447
00448 } else if (controller.empty()) {
00449 send_and_record_server_message(player_name + " takes control of side " + side + ".");
00450 side_controllers_[side_num] = "human";
00451 } else {
00452 send_and_record_server_message(player_name + (controller == "human_ai" ? " " : " un")
00453 + "droids side " + side + ".");
00454 side_controllers_[side_num] = (controller == "human_ai" ? "ai" : "human");
00455 }
00456
00457 simple_wml::document response;
00458 simple_wml::node& change = response.root().add_child("change_controller");
00459
00460 change.set_attr("side", side.c_str());
00461 change.set_attr("player", player_name.c_str());
00462
00463
00464 change.set_attr("controller", (side_controllers_[side_num] == "ai" ? "network_ai" : "network"));
00465 send_data(response, sock);
00466
00467
00468
00469
00470 if (!player_left) {
00471 change.set_attr("controller", (side_controllers_[side_num] == "ai" ? "human_ai" : "human"));
00472 wesnothd::send_to_one(response, sock);
00473 }
00474
00475
00476 if (started_) {
00477 const simple_wml::node::child_list& side_list = level_.root().children("side");
00478 assert(side_num < side_list.size());
00479 side_list[side_num]->set_attr_dup("current_player", player_name.c_str());
00480
00481 side_list[side_num]->set_attr_dup("controller", side_controllers_[side_num].c_str());
00482 }
00483 }
00484
00485 void game::notify_new_host(){
00486 const std::string owner_name = username(player_info_->find(owner_));
00487 simple_wml::document cfg;
00488 simple_wml::node& cfg_host_transfer = cfg.root().add_child("host_transfer");
00489
00490
00491 cfg_host_transfer.set_attr("name", owner_name.c_str());
00492 cfg_host_transfer.set_attr("value", "1");
00493 std::string message = owner_name + " has been chosen as the new host.";
00494 if (!wesnothd::send_to_one(cfg, owner_)) {
00495 message += " But an internal error occurred. You probably have to abandon this game.";
00496 }
00497 send_and_record_server_message(message);
00498 }
00499
00500 bool game::describe_slots() {
00501 if(started_ || description_ == NULL)
00502 return false;
00503
00504 int available_slots = 0;
00505 int num_sides = level_.root().children("side").size();
00506 int i = 0;
00507 const simple_wml::node::child_list& side_list = level_.root().children("side");
00508 for(simple_wml::node::child_list::const_iterator it = side_list.begin(); it != side_list.end(); ++it, ++i) {
00509 if (((**it)["allow_player"].to_bool(true) == false) || (**it)["controller"] == "null") {
00510 num_sides--;
00511 } else {
00512 if (sides_[i] == 0) ++available_slots;
00513 }
00514 }
00515 char buf[50];
00516 snprintf(buf,sizeof(buf), "%d/%d", available_slots, num_sides);
00517
00518 if ((*description_)["slots"] != buf) {
00519 description_->set_attr_dup("slots", buf);
00520 return true;
00521 } else {
00522 return false;
00523 }
00524 }
00525
00526 bool game::player_is_banned(const network::connection sock) const {
00527 std::vector<std::string>::const_iterator ban =
00528 std::find(bans_.begin(), bans_.end(), network::ip_address(sock));
00529 return ban != bans_.end();
00530 }
00531
00532 void game::mute_all_observers() {
00533 all_observers_muted_ = !all_observers_muted_;
00534 if (all_observers_muted_) {
00535 send_and_record_server_message("All observers have been muted.");
00536 } else {
00537 send_and_record_server_message("Muting of all observers has been removed.");
00538 }
00539 }
00540
00541 void game::send_muted_observers(const player_map::const_iterator user) const
00542 {
00543 if (all_observers_muted_) {
00544 send_server_message("All observers are muted.", user->first);
00545 return;
00546 }
00547 std::string muted_nicks = list_users(muted_observers_, __func__);
00548
00549 send_server_message("Muted observers: " + muted_nicks, user->first);
00550 }
00551
00552 void game::mute_observer(const simple_wml::node& mute,
00553 const player_map::const_iterator muter)
00554 {
00555 if (muter->first != owner_) {
00556 send_server_message("You cannot mute: not the game host.", muter->first);
00557 return;
00558 }
00559 const simple_wml::string_span& username = mute["username"];
00560 if (username.empty()) {
00561 send_muted_observers(muter);
00562 return;
00563 }
00564
00565 const player_map::const_iterator user = find_user(username);
00566
00567
00568
00569
00570 if (user == player_info_->end() || !is_observer(user->first)) {
00571 send_server_message("Observer '" + username.to_string() + "' not found.", muter->first);
00572 return;
00573 }
00574
00575
00576 if (user->first == muter->first) {
00577 send_server_message("Don't mute yourself, silly.", muter->first);
00578 return;
00579 }
00580 if (is_muted_observer(user->first)) {
00581 send_server_message(username.to_string() + " is already muted.", muter->first);
00582 return;
00583 }
00584 LOG_GAME << network::ip_address(muter->first) << "\t"
00585 << muter->second.name() << " muted: " << username << " ("
00586 << network::ip_address(user->first) << ")\tin game:\t\""
00587 << name_ << "\" (" << id_ << ")\n";
00588 muted_observers_.push_back(user->first);
00589 send_and_record_server_message(username.to_string() + " has been muted.");
00590 }
00591
00592 void game::unmute_observer(const simple_wml::node& unmute,
00593 const player_map::const_iterator unmuter)
00594 {
00595 if (unmuter->first != owner_) {
00596 send_server_message("You cannot unmute: not the game host.", unmuter->first);
00597 return;
00598 }
00599 const simple_wml::string_span& username = unmute["username"];
00600 if (username.empty()) {
00601 muted_observers_.clear();
00602 send_and_record_server_message("Everyone has been unmuted.");
00603 return;
00604 }
00605
00606 const player_map::const_iterator user = find_user(username);
00607 if (user == player_info_->end() || !is_observer(user->first)) {
00608 send_server_message("Observer '" + username.to_string() + "' not found.", unmuter->first);
00609 return;
00610 }
00611
00612 if (!is_muted_observer(user->first)) {
00613 send_server_message(username.to_string() + " is not muted.", unmuter->first);
00614 return;
00615 }
00616
00617 LOG_GAME << network::ip_address(unmuter->first) << "\t"
00618 << unmuter->second.name() << " unmuted: " << username << " ("
00619 << network::ip_address(user->first) << ")\tin game:\t\""
00620 << name_ << "\" (" << id_ << ")\n";
00621 muted_observers_.erase(std::remove(muted_observers_.begin(),
00622 muted_observers_.end(), user->first), muted_observers_.end());
00623 send_and_record_server_message(username.to_string() + " has been unmuted.");
00624 }
00625
00626 void game::send_leave_game(network::connection user) const
00627 {
00628 static simple_wml::document leave_game("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
00629 wesnothd::send_to_one(leave_game, user);
00630 }
00631
00632 network::connection game::kick_member(const simple_wml::node& kick,
00633 const player_map::const_iterator kicker)
00634 {
00635 if (kicker->first != owner_) {
00636 send_server_message("You cannot kick: not the game host", kicker->first);
00637 return 0;
00638 }
00639 const simple_wml::string_span& username = kick["username"];
00640 const player_map::const_iterator user = find_user(username);
00641 if (user == player_info_->end() || !is_member(user->first)) {
00642 send_server_message("'" + username.to_string() + "' is not a member of this game.", kicker->first);
00643 return 0;
00644 } else if (user->first == kicker->first) {
00645 send_server_message("Don't kick yourself, silly.", kicker->first);
00646 return 0;
00647 } else if (user->second.is_moderator()) {
00648 send_server_message("You're not allowed to kick a moderator.", kicker->first);
00649 return 0;
00650 }
00651 LOG_GAME << network::ip_address(kicker->first) << "\t"
00652 << kicker->second.name() << "\tkicked: " << username << " ("
00653 << network::ip_address(user->first) << ")\tfrom game:\t\""
00654 << name_ << "\" (" << id_ << ")\n";
00655 send_and_record_server_message(username.to_string() + " has been kicked.");
00656
00657
00658 send_leave_game(user->first);
00659 remove_player(user->first);
00660 return user->first;
00661 }
00662
00663 network::connection game::ban_user(const simple_wml::node& ban,
00664 const player_map::const_iterator banner)
00665 {
00666 if (banner->first != owner_) {
00667 send_server_message("You cannot ban: not the game host", banner->first);
00668 return 0;
00669 }
00670 const simple_wml::string_span& username = ban["username"];
00671 const player_map::const_iterator user = find_user(username);
00672 if (user == player_info_->end()) {
00673 send_server_message("User '" + username.to_string() + "' not found.", banner->first);
00674 return 0;
00675 } else if (user->first == banner->first) {
00676 send_server_message("Don't ban yourself, silly.", banner->first);
00677 return 0;
00678 } else if (player_is_banned(user->first)) {
00679 send_server_message("'" + username.to_string() + "' is already banned.", banner->first);
00680 return 0;
00681 } else if (user->second.is_moderator()) {
00682 send_server_message("You're not allowed to ban a moderator.", banner->first);
00683 return 0;
00684 }
00685 LOG_GAME << network::ip_address(banner->first) << "\t"
00686 << banner->second.name() << "\tbanned: " << username << " ("
00687 << network::ip_address(user->first) << ")\tfrom game:\t\""
00688 << name_ << "\" (" << id_ << ")\n";
00689 bans_.push_back(network::ip_address(user->first));
00690 send_and_record_server_message(username.to_string() + " has been banned.");
00691 if (is_member(user->first)) {
00692
00693 send_leave_game(user->first);
00694 remove_player(user->first);
00695 return user->first;
00696 }
00697
00698 return 0;
00699 }
00700
00701 void game::unban_user(const simple_wml::node& unban,
00702 const player_map::const_iterator unbanner)
00703 {
00704 if (unbanner->first != owner_) {
00705 send_server_message("You cannot unban: not the game host.", unbanner->first);
00706 return;
00707 }
00708 const simple_wml::string_span& username = unban["username"];
00709 const player_map::const_iterator user = find_user(username);
00710 if (user == player_info_->end()) {
00711 send_server_message("User '" + username.to_string() + "' not found.", unbanner->first);
00712 return;
00713 }
00714 if (!player_is_banned(user->first)) {
00715 send_server_message("'" + username.to_string() + "' is not banned.", unbanner->first);
00716 return;
00717 }
00718 LOG_GAME << network::ip_address(unbanner->first) << "\t"
00719 << unbanner->second.name() << "\tunbanned: " << username << " ("
00720 << network::ip_address(user->first) << ")\tfrom game:\t\""
00721 << name_ << "\" (" << id_ << ")\n";
00722 bans_.erase(std::remove(bans_.begin(), bans_.end(), network::ip_address(user->first)), bans_.end());
00723 send_and_record_server_message(username.to_string() + " has been unbanned.");
00724 }
00725
00726 void game::process_message(simple_wml::document& data, const player_map::iterator user) {
00727 if (owner_ == 0) {
00728 ERR_GAME << "No owner in game::process_message\n";
00729 }
00730
00731 simple_wml::node* const message = data.root().child("message");
00732 assert(message);
00733 message->set_attr_dup("sender", user->second.name().c_str());
00734
00735 const simple_wml::string_span& msg = (*message)["message"];
00736 chat_message::truncate_message(msg, *message);
00737
00738 send_data(data, user->first, "game message");
00739 }
00740
00741 bool game::is_legal_command(const simple_wml::node& command, bool is_player) {
00742
00743 if (!command.one_child()) return false;
00744
00745 if (command.child("speak") || command.child("global_variable")) return true;
00746 if (is_player && command.child("global_variable")) {
00747 const simple_wml::node *gvar = (command.child("global_variable"));
00748 if ((*gvar)["side"].to_int() == global_wait_side_) {
00749 global_wait_side_ = 0;
00750 return true;
00751 }
00752 return false;
00753 }
00754 if (is_player
00755 && (command.child("label")
00756 || command.child("clear_labels")
00757 || command.child("rename")
00758 || command.child("countdown_update")
00759 ))
00760 {
00761 return true;
00762 }
00763 return false;
00764 }
00765
00766 bool game::process_turn(simple_wml::document& data, const player_map::const_iterator user) {
00767
00768 if (!started_) return false;
00769 simple_wml::node* const turn = data.root().child("turn");
00770 bool turn_ended = false;
00771
00772
00773
00774 bool repackage = false;
00775 int index = 0;
00776 std::vector<int> marked;
00777 const simple_wml::node::child_list& commands = turn->children("command");
00778 simple_wml::node::child_list::const_iterator command;
00779 const bool player = (is_player(user->first) || user->first == owner_);
00780 for (command = commands.begin(); command != commands.end(); ++command) {
00781 if (!is_current_player(user->first)
00782 && !is_legal_command(**command, player)) {
00783 LOG_GAME << "ILLEGAL COMMAND in game: " << id_ << " ((("
00784 << simple_wml::node_to_string(**command) << ")))\n";
00785 std::stringstream msg;
00786 msg << "Removing illegal command '" << (**command).first_child().to_string()
00787 << "' from: " << user->second.name()
00788 << ". Current player is: "
00789 << username(player_info_->find(current_player()))
00790 << " (" << end_turn_ + 1 << "/" << nsides_ << ").";
00791 LOG_GAME << msg.str() << " (socket: " << current_player()
00792 << ") (game id: " << id_ << ")\n";
00793 send_and_record_server_message(msg.str());
00794
00795 marked.push_back(index - marked.size());
00796 } else if ((**command).child("speak")) {
00797 simple_wml::node& speak = *(**command).child("speak");
00798 if (speak["team_name"] != "" || is_muted_observer(user->first)) {
00799 DBG_GAME << "repackaging..." << std::endl;
00800 repackage = true;
00801 }
00802
00803 const simple_wml::string_span& msg = speak["message"];
00804 chat_message::truncate_message(msg, speak);
00805
00806
00807
00808 speak.set_attr_dup("id", user->second.name().c_str());
00809
00810 if (is_player(user->first)) {
00811 const size_t side_num = speak["side"].to_int();
00812 if (side_num < 1 || side_num > gamemap::MAX_PLAYERS
00813 || sides_[side_num - 1] != user->first) {
00814 if (user->first == current_player()) {
00815 speak.set_attr_dup("side", lexical_cast<std::string>(current_side() + 1).c_str());
00816 } else {
00817 const side_vector::const_iterator s =
00818 std::find(sides_.begin(), sides_.end(), user->first);
00819 speak.set_attr_dup("side", lexical_cast<std::string>(s - sides_.begin() + 1).c_str());
00820 }
00821 }
00822 }
00823 } else if (is_current_player(user->first) && (**command).child("end_turn")) {
00824 turn_ended = end_turn();
00825 }
00826 ++index;
00827 }
00828 for(std::vector<int>::const_iterator j = marked.begin(); j != marked.end(); ++j) {
00829 turn->remove_child("command",*j);
00830 }
00831 for (command = commands.begin(); command != commands.end(); ++command) {
00832 if (simple_wml::node* attack = (**command).child("attack")) {
00833 int seed = rand() & 0x7FFFFFFF;
00834 attack->set_attr_int("seed", seed);
00835 simple_wml::document doc;
00836 simple_wml::node& rs = doc.root().add_child("random_seed");
00837 rs.set_attr_int("seed", seed);
00838 wesnothd::send_to_one(doc, user->first, "game replay");
00839 }
00840 }
00841 if (turn->no_children()) {
00842 return false;
00843 }
00844 if (!repackage) {
00845 record_data(data.clone());
00846 send_data(data, user->first, "game replay");
00847 return turn_ended;
00848 }
00849 for (command = commands.begin(); command != commands.end(); ++command) {
00850 simple_wml::node* const speak = (**command).child("speak");
00851 if (speak == NULL) {
00852 simple_wml::document* mdata = new simple_wml::document;
00853 simple_wml::node& turn = mdata->root().add_child("turn");
00854 (**command).copy_into(turn.add_child("command"));
00855 send_data(*mdata, user->first, "game replay");
00856 record_data(mdata);
00857 continue;
00858 }
00859 const simple_wml::string_span& team_name = (*speak)["team_name"];
00860
00861 if (team_name == game_config::observer_team_name.c_str()) {
00862
00863 } else if (is_muted_observer(user->first)) {
00864 send_server_message("You have been muted, others can't see your message!", user->first);
00865 continue;
00866
00867 } else if (!is_on_team(team_name, user->first)) {
00868 std::ostringstream msg;
00869 msg << "Removing illegal message from " << user->second.name() << " to " << std::string(team_name.begin(), team_name.end()) << ".";
00870 const std::string& msg_str = msg.str();
00871 LOG_GAME << msg_str << std::endl;
00872 send_and_record_server_message(msg_str);
00873 continue;
00874 }
00875
00876 std::auto_ptr<simple_wml::document> message(new simple_wml::document);
00877 simple_wml::node& turn = message->root().add_child("turn");
00878 simple_wml::node& command = turn.add_child("command");
00879 speak->copy_into(command.add_child("speak"));
00880 if (team_name == "") {
00881 send_data(*message, user->first, "game message");
00882 record_data(message.release());
00883 } else if (team_name == game_config::observer_team_name) {
00884 wesnothd::send_to_many(*message, observers_, user->first, "game message");
00885 record_data(message.release());
00886 } else {
00887 send_data_team(*message, team_name, user->first, "game message");
00888 }
00889 }
00890 return turn_ended;
00891 }
00892
00893 void game::process_whiteboard(simple_wml::document& data, const player_map::const_iterator user)
00894 {
00895 if(!started_ || !is_player(user->first))
00896 return;
00897
00898 simple_wml::node const& wb_node = *data.child("whiteboard");
00899
00900
00901 simple_wml::string_span const& team_name = wb_node["team_name"];
00902 size_t const side_num = wb_node["side"].to_int();
00903 if(!is_on_team(team_name,user->first)
00904 || side_num < 1
00905 || side_num > gamemap::MAX_PLAYERS
00906 || sides_[side_num-1] != user->first)
00907 {
00908 std::ostringstream msg;
00909 msg << "Ignoring illegal whiteboard data, sent from user '" << user->second.name()
00910 << "' to team '" << std::string(team_name.begin(), team_name.end()) << "'." << std::endl;
00911 const std::string& msg_str = msg.str();
00912 LOG_GAME << msg_str << std::endl;
00913 send_and_record_server_message(msg_str);
00914 return;
00915 }
00916
00917 send_data_team(data,team_name,user->first,"whiteboard");
00918 }
00919
00920 bool game::end_turn() {
00921
00922 ++end_turn_;
00923 bool turn_ended = false;
00924 if ((current_side()) == 0) {
00925 turn_ended = true;
00926 }
00927
00928 for (int i = 0; i < nsides_ && nsides_ <= gamemap::MAX_PLAYERS && side_controllers_[current_side()] == "null"; ++i) {
00929 ++end_turn_;
00930 if (current_side() == 0) {
00931 turn_ended = true;
00932 }
00933 }
00934 if (!turn_ended) return false;
00935
00936 if (description_ == NULL) {
00937 return false;
00938 }
00939
00940 description_->set_attr_dup("turn", describe_turns(current_turn(), level_["turns"]).c_str());
00941
00942 return true;
00943 }
00944
00945
00946
00947 bool game::add_player(const network::connection player, bool observer) {
00948 if(is_member(player)) {
00949 ERR_GAME << "ERROR: Player is already in this game. (socket: "
00950 << player << ")\n";
00951 return false;
00952 }
00953 const player_map::iterator user = player_info_->find(player);
00954 if (user == player_info_->end()) {
00955 missing_user(player, __func__);
00956 return false;
00957 }
00958 DBG_GAME << debug_player_info();
00959 bool became_observer = false;
00960 if (!started_ && !observer && take_side(user)) {
00961 DBG_GAME << "adding player...\n";
00962 players_.push_back(player);
00963 user->second.set_status(player::PLAYING);
00964 send_and_record_server_message(user->second.name() + " has joined the game.", player);
00965 } else if (!allow_observers() && !user->second.is_moderator()) {
00966 return false;
00967 } else {
00968 if (!observer) {
00969 became_observer = true;
00970 observer = true;
00971 }
00972 DBG_GAME << "adding observer...\n";
00973 observers_.push_back(player);
00974 if (!allow_observers()) send_and_record_server_message(user->second.name() + " is now observing the game.", player);
00975
00976 simple_wml::document observer_join;
00977 observer_join.root().add_child("observer").set_attr_dup("name", user->second.name().c_str());
00978
00979
00980 send_data(observer_join, player);
00981 }
00982 LOG_GAME << network::ip_address(player) << "\t" << user->second.name()
00983 << "\tjoined game:\t\"" << name_ << "\" (" << id_ << ")"
00984 << (observer ? " as an observer" : "")
00985 << ". (socket: " << player << ")\n";
00986 user->second.mark_available(id_, name_);
00987 user->second.set_status((observer) ? player::OBSERVING : player::PLAYING);
00988 DBG_GAME << debug_player_info();
00989
00990 if (!wesnothd::send_to_one(level_, player)) return false;
00991
00992 if(started_) {
00993
00994 static simple_wml::document start_game_doc("[start_game]\n[/start_game]\n", simple_wml::INIT_COMPRESSED);
00995 if (!wesnothd::send_to_one(start_game_doc, player)) return false;
00996
00997
00998
00999 send_observerjoins(player);
01000
01001 send_history(player);
01002 } else {
01003 send_user_list();
01004 }
01005
01006 const std::string clones = has_same_ip(player, observer);
01007 if (!clones.empty()) {
01008 send_and_record_server_message(user->second.name() + " has the same IP as: " + clones);
01009 }
01010
01011 if (became_observer) {
01012
01013 send_server_message("You are an observer.", player);
01014 }
01015 return true;
01016 }
01017
01018 bool game::remove_player(const network::connection player, const bool disconnect, const bool destruct) {
01019 if (!is_member(player)) {
01020 ERR_GAME << "ERROR: User is not in this game. (socket: "
01021 << player << ")\n";
01022 return false;
01023 }
01024 DBG_GAME << debug_player_info();
01025 DBG_GAME << "removing player...\n";
01026
01027 const bool host = (player == owner_);
01028 const bool observer = is_observer(player);
01029 players_.erase(std::remove(players_.begin(), players_.end(), player), players_.end());
01030 observers_.erase(std::remove(observers_.begin(), observers_.end(), player), observers_.end());
01031 const bool game_ended = players_.empty() || (host && !started_);
01032 const player_map::iterator user = player_info_->find(player);
01033 if (user == player_info_->end()) {
01034 missing_user(player, __func__);
01035 return game_ended;
01036 }
01037 LOG_GAME << network::ip_address(user->first) << "\t" << user->second.name()
01038 << ((game_ended && !(observer && destruct))
01039 ? (started_ ? "\tended" : "\taborted") : "\thas left")
01040 << " game:\t\"" << name_ << "\" (" << id_ << ")"
01041 << (game_ended && started_ && !(observer && destruct) ? " at turn: "
01042 + lexical_cast_default<std::string,size_t>(current_turn())
01043 + " with reason: '" + termination_reason() + "'" : "")
01044 << (observer ? " as an observer" : "")
01045 << (disconnect ? " and disconnected" : "")
01046 << ". (socket: " << user->first << ")\n";
01047 if (game_ended && started_ && !(observer && destruct)) {
01048 send_server_message_to_all(user->second.name() + " ended the game.", player);
01049 }
01050 if (game_ended || destruct) return game_ended;
01051
01052
01053
01054 if (!disconnect) {
01055 user->second.mark_available();
01056 }
01057 if (observer) {
01058 send_observerquit(user);
01059 } else {
01060 send_and_record_server_message(user->second.name()
01061 + (disconnect ? " has disconnected." : " has left the game."), player);
01062 }
01063
01064 if (host) {
01065 owner_ = players_.front();
01066 notify_new_host();
01067 }
01068
01069 bool ai_transfer = false;
01070
01071
01072 for (side_vector::iterator side = sides_.begin(); side != sides_.end(); ++side) {
01073 size_t side_num = side - sides_.begin();
01074 if (*side != player) continue;
01075 if (side_controllers_[side_num] == "ai") ai_transfer = true;
01076
01077 player_map::iterator o = player_info_->find(owner_);
01078 change_controller(side_num, owner_, username(o));
01079
01080 if (!is_player(owner_)) {
01081 DBG_GAME << "making the owner a player...\n";
01082 o->second.set_status(player::PLAYING);
01083 observers_.erase(std::remove(observers_.begin(), observers_.end(), owner_), observers_.end());
01084 players_.push_back(owner_);
01085 send_observerquit(o);
01086 }
01087
01088
01089 const std::string side_drop = lexical_cast<std::string, size_t>(side_num + 1);
01090 simple_wml::document drop;
01091 drop.root().set_attr("side_drop", side_drop.c_str());
01092 drop.root().set_attr("controller", side_controllers_[side_num].c_str());
01093
01094 wesnothd::send_to_one(drop, owner_);
01095 }
01096 if (ai_transfer) send_and_record_server_message("AI sides transferred to host.");
01097
01098 DBG_GAME << debug_player_info();
01099
01100 send_user_list(player);
01101 return false;
01102 }
01103
01104 void game::send_user_list(const network::connection exclude) const {
01105
01106
01107 if (started_ || description_ == NULL) return;
01108
01109 simple_wml::document cfg;
01110 cfg.root().add_child("gamelist");
01111 user_vector users = all_game_users();
01112 for(user_vector::const_iterator p = users.begin(); p != users.end(); ++p) {
01113 const player_map::const_iterator pl = player_info_->find(*p);
01114 if (pl != player_info_->end()) {
01115
01116
01117 cfg.root().add_child("user").set_attr("name", pl->second.name().c_str());
01118 }
01119 }
01120 send_data(cfg, exclude);
01121 }
01122
01123 void game::load_next_scenario(const player_map::const_iterator user) const {
01124 send_server_message_to_all(user->second.name() + " advances to the next scenario", user->first);
01125 simple_wml::document cfg_scenario;
01126 level_.root().copy_into(cfg_scenario.root().add_child("next_scenario"));
01127 if (!wesnothd::send_to_one(cfg_scenario, user->first)) return;
01128
01129 send_history(user->first);
01130
01131 send_observerjoins(user->first);
01132 }
01133
01134 void game::send_data(simple_wml::document& data,
01135 const network::connection exclude,
01136 std::string packet_type) const
01137 {
01138 wesnothd::send_to_many(data, all_game_users(), exclude, packet_type);
01139 }
01140
01141 void game::send_data_team(simple_wml::document& data,
01142 const simple_wml::string_span& team,
01143 const network::connection exclude,
01144 std::string packet_type) const
01145 {
01146 DBG_GAME << __func__ << "...\n";
01147 wesnothd::send_to_many(data, players_,
01148 boost::bind(&game::is_on_team, this, boost::ref(team), _1),
01149 exclude, packet_type);
01150 }
01151
01152
01153 bool game::is_on_team(const simple_wml::string_span& team, const network::connection player) const {
01154 const simple_wml::node::child_list& side_list = level_.root().children("side");
01155 for (side_vector::const_iterator side = sides_.begin(); side != sides_.end(); ++side) {
01156 if (*side != player) continue;
01157 for (simple_wml::node::child_list::const_iterator i = side_list.begin();
01158 i != side_list.end(); ++i) {
01159 if ((**i)["side"].to_int() != side - sides_.begin() + 1) continue;
01160 if ((**i)["team_name"] != team) continue;
01161
01162 if ((**i)["controller"] == "ai") continue;
01163 if (side_controllers_[side - sides_.begin()] == "ai") continue;
01164 DBG_GAME << "side: " << (**i)["side"].to_int() << " with team_name: " << (**i)["team_name"]
01165 << " belongs to player: " << player << std::endl;
01166 return true;
01167 }
01168 }
01169
01170 return false;
01171 }
01172
01173 std::string game::has_same_ip(const network::connection& user, bool observer) const {
01174 const user_vector users = observer ? players_ : all_game_users();
01175 const std::string ip = network::ip_address(user);
01176 std::string clones;
01177 for (user_vector::const_iterator i = users.begin(); i != users.end(); ++i) {
01178 if (ip == network::ip_address(*i) && user != *i) {
01179 const player_map::const_iterator pl = player_info_->find(*i);
01180 if (pl != player_info_->end()) {
01181 clones += (clones.empty() ? "" : ", ") + pl->second.name();
01182 }
01183 }
01184 }
01185 return clones;
01186 }
01187
01188 void game::send_observerjoins(const network::connection sock) const {
01189 for (user_vector::const_iterator ob = observers_.begin(); ob != observers_.end(); ++ob) {
01190 if (*ob == sock) continue;
01191 const player_map::const_iterator obs = player_info_->find(*ob);
01192 if (obs == player_info_->end()) {
01193 missing_user(*ob, __func__);
01194 continue;
01195 }
01196
01197 simple_wml::document cfg;
01198 cfg.root().add_child("observer").set_attr_dup("name", obs->second.name().c_str());
01199 if (sock == 0) {
01200
01201 send_data(cfg, *ob);
01202 } else {
01203
01204 wesnothd::send_to_one(cfg, sock);
01205 }
01206 }
01207 }
01208
01209 void game::send_observerquit(const player_map::const_iterator observer) const {
01210 if (observer == player_info_->end()) {
01211 return;
01212 }
01213 simple_wml::document observer_quit;
01214
01215
01216
01217 observer_quit.root().add_child("observer_quit").set_attr("name", observer->second.name().c_str());
01218 send_data(observer_quit, observer->first);
01219 }
01220
01221 void game::send_history(const network::connection sock) const
01222 {
01223 if(history_.empty()) {
01224 return;
01225 }
01226
01227
01228
01229
01230 std::string buf;
01231 for(std::vector<simple_wml::document*>::iterator i = history_.begin();
01232 i != history_.end(); ++i) {
01233 buf += (*i)->output();
01234 delete *i;
01235 }
01236
01237 try {
01238 simple_wml::document* doc = new simple_wml::document(buf.c_str(), simple_wml::INIT_STATIC);
01239 const simple_wml::string_span& data = doc->output_compressed();
01240 doc->compress();
01241 network::send_raw_data(data.begin(), data.size(), sock,"game_history");
01242 history_.clear();
01243 history_.push_back(doc);
01244 } catch (simple_wml::error& e) {
01245 WRN_CONFIG << __func__ << ": simple_wml error: " << e.message << std::endl;
01246 }
01247
01248 }
01249
01250 static bool is_invalid_filename_char(char c) {
01251 return !(isalnum(c) || (c == '_') || (c == '-') || (c == '.')
01252 || (c == '(') || (c == ')') || (c == '#') || (c == ',')
01253 || (c == '!') || (c == '?') || (c == '^') || (c == '+')
01254 || (c == '*') || (c == ':') || (c == '=') || (c == '@')
01255 || (c == '%') || (c == '\''));
01256 }
01257
01258 void game::save_replay() {
01259 if (!save_replays_ || !started_ || history_.empty()) return;
01260
01261 std::string replay_commands;
01262 for(std::vector<simple_wml::document*>::iterator i = history_.begin();
01263 i != history_.end(); ++i) {
01264 const simple_wml::node::child_list& turn_list = (*i)->root().children("turn");
01265 for (simple_wml::node::child_list::const_iterator turn = turn_list.begin();
01266 turn != turn_list.end(); ++turn) {
01267 replay_commands += simple_wml::node_to_string(**turn);
01268 }
01269 delete *i;
01270 }
01271 history_.clear();
01272
01273 std::stringstream name;
01274 name << level_["name"] << " Turn " << current_turn();
01275
01276 std::stringstream replay_data;
01277 try {
01278 replay_data << "campaign_type=\"multiplayer\"\n"
01279 << "difficulty=\"NORMAL\"\n"
01280 << "label=\"" << name.str() << "\"\n"
01281 << "mp_game_title=\"" << name_ << "\"\n"
01282 << "random_seed=\"" << level_["random_seed"] << "\"\n"
01283 << "version=\"" << level_["version"] << "\"\n"
01284 << "[replay]\n" << replay_commands << "[/replay]\n"
01285 << "[replay_start]\n" << level_.output() << "[/replay_start]\n";
01286
01287 name << " (" << id_ << ").gz";
01288
01289 std::string replay_data_str = replay_data.str();
01290 simple_wml::document replay(replay_data_str.c_str(), simple_wml::INIT_STATIC);
01291
01292 std::string filename(name.str());
01293 std::replace(filename.begin(), filename.end(), ' ', '_');
01294 filename.erase(std::remove_if(filename.begin(), filename.end(), is_invalid_filename_char), filename.end());
01295 DBG_GAME << "saving replay: " << filename << std::endl;
01296 scoped_ostream os(ostream_file(replay_save_path_ + filename));
01297 (*os) << replay.output_compressed();
01298
01299 if (!os->good()) {
01300 ERR_GAME << "Could not save replay! (" << filename << ")\n";
01301 }
01302 } catch (simple_wml::error& e) {
01303 WRN_CONFIG << __func__ << ": simple_wml error: " << e.message << std::endl;
01304 }
01305 }
01306
01307 void game::record_data(simple_wml::document* data) {
01308 data->compress();
01309 history_.push_back(data);
01310 }
01311
01312 void game::clear_history() {
01313 if (history_.empty()) return;
01314 for(std::vector<simple_wml::document*>::iterator i = history_.begin(); i != history_.end(); ++i) {
01315 delete *i;
01316 }
01317 history_.clear();
01318 }
01319
01320 void game::set_description(simple_wml::node* desc) {
01321 description_ = desc;
01322 if(!password_.empty()) {
01323 description_->set_attr("password", "yes");
01324 }
01325 }
01326
01327 void game::set_termination_reason(const std::string& reason) {
01328
01329
01330
01331
01332
01333
01334
01335 if (termination_.empty()) { termination_ = reason; }
01336 }
01337
01338 void game::allow_global(const simple_wml::document &data) {
01339 const simple_wml::node *cfg = data.root().child("wait_global");
01340 int side = (*cfg)["side"].to_int();
01341 if ((side < 0) || (side > nsides_)) side = 0;
01342 global_wait_side_ = side;
01343 }
01344
01345 const user_vector game::all_game_users() const {
01346 user_vector res;
01347
01348 res.insert(res.end(), players_.begin(), players_.end());
01349 res.insert(res.end(), observers_.begin(), observers_.end());
01350
01351 return res;
01352 }
01353
01354 std::string game::debug_player_info() const {
01355 std::stringstream result;
01356 result << "game id: " << id_ << "\n";
01357
01358 for (user_vector::const_iterator p = players_.begin(); p != players_.end(); ++p){
01359 const player_map::const_iterator user = player_info_->find(*p);
01360 if (user != player_info_->end()){
01361 result << "player: " << user->second.name().c_str() << "\n";
01362 }
01363 else{
01364 result << "player: '" << *p << "' not found\n";
01365 }
01366 }
01367
01368 for (user_vector::const_iterator o = observers_.begin(); o != observers_.end(); ++o){
01369 const player_map::const_iterator user = player_info_->find(*o);
01370 if (user != player_info_->end()){
01371 result << "observer: " << user->second.name().c_str() << "\n";
01372 }
01373 else{
01374 result << "observer: '" << *o << "' not found\n";
01375 }
01376 }
01377
01378
01379
01380
01381
01382 return result.str();
01383 }
01384
01385 player_map::iterator game::find_user(const simple_wml::string_span& name)
01386 {
01387 player_map::iterator pl;
01388 for (pl = player_info_->begin(); pl != player_info_->end(); ++pl) {
01389 if (name == pl->second.name().c_str()) {
01390 break;
01391 }
01392 }
01393 return pl;
01394 }
01395
01396 void game::send_and_record_server_message(const char* message, const network::connection exclude)
01397 {
01398 simple_wml::document* doc = new simple_wml::document;
01399 send_server_message(message, 0, doc);
01400 send_data(*doc, exclude, "message");
01401 if (started_) record_data(doc);
01402 }
01403
01404 void game::send_server_message_to_all(const char* message, network::connection exclude) const
01405 {
01406 simple_wml::document doc;
01407 send_server_message(message, 0, &doc);
01408 send_data(doc, exclude, "message");
01409 }
01410
01411 void game::send_server_message(const char* message, network::connection sock, simple_wml::document* docptr) const
01412 {
01413 simple_wml::document docbuf;
01414 if(docptr == NULL) {
01415 docptr = &docbuf;
01416 }
01417
01418 simple_wml::document& doc = *docptr;
01419 if (started_) {
01420 simple_wml::node& cmd = doc.root().add_child("turn");
01421 simple_wml::node& cfg = cmd.add_child("command");
01422 simple_wml::node& msg = cfg.add_child("speak");
01423 msg.set_attr("id", "server");
01424 msg.set_attr_dup("message", message);
01425 } else {
01426 simple_wml::node& msg = doc.root().add_child("message");
01427 msg.set_attr("sender", "server");
01428 msg.set_attr_dup("message", message);
01429 }
01430
01431
01432 if(sock) {
01433 wesnothd::send_to_one(doc, sock, "message");
01434 }
01435 }
01436 }