game.cpp

Go to the documentation of this file.
00001 /* $Id: game.cpp 26160 2008-04-27 06:13:02Z soliton $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 #include "../global.hpp"
00016 
00017 #include "../game_config.hpp" // game_config::observer_team_name
00018 #include "../log.hpp"
00019 #include "../map.hpp" // gamemap::MAX_PLAYERS
00020 
00021 #include "game.hpp"
00022 #include "player.hpp"
00023 
00024 #include <algorithm>
00025 #include <iostream>
00026 #include <memory>
00027 #include <cassert>
00028 #include <sstream>
00029 
00030 #define ERR_GAME LOG_STREAM(err, mp_server)
00031 #define WRN_GAME LOG_STREAM(warn, mp_server)
00032 #define LOG_GAME LOG_STREAM(info, mp_server)
00033 #define DBG_GAME LOG_STREAM(debug, mp_server)
00034 
00035 namespace chat_message {
00036 
00037 const size_t max_message_length = 256;
00038 static void truncate_message(const simple_wml::string_span& str, simple_wml::node& message) {
00039     // testing for msg.size() is not sufficient but we're not getting false negatives
00040     // and it's cheaper than always converting to wstring.
00041     if(str.size() > chat_message::max_message_length) {
00042         std::string tmp(str.begin(), str.end());
00043         // The string can contain utf-8 characters so truncate as wide_string otherwise
00044         // a corrupted utf-8 string can be returned.
00045         utils::truncate_as_wstring(tmp, max_message_length);
00046         message.set_attr_dup("message", tmp.c_str());
00047     }
00048 }
00049 
00050 } // end chat_message namespace
00051 
00052 int game::id_num = 1;
00053 
00054 game::game(player_map& players, const network::connection host, const std::string name)
00055     : player_info_(&players), id_(id_num++), name_(name), owner_(host),
00056     sides_(gamemap::MAX_PLAYERS), sides_taken_(gamemap::MAX_PLAYERS),
00057     side_controllers_(gamemap::MAX_PLAYERS), nsides_(0), started_(false),
00058     description_(NULL), end_turn_(0), all_observers_muted_(false)
00059 {
00060     // Hack to handle the pseudo games lobby_ and not_logged_in_.
00061     if (owner_ == 0) return;
00062     players_.push_back(owner_);
00063     const player_map::iterator pl = player_info_->find(owner_);
00064     if (pl == player_info_->end()) {
00065         ERR_GAME << "ERROR: Could not find host in player_info_. (socket: "
00066             << owner_ << ")\n";
00067         return;
00068     }
00069     // Mark the host as unavailable in the lobby.
00070     pl->second.mark_available(id_, name_);
00071 
00072 }
00073 
00074 game::~game()
00075 {
00076     for(std::vector<simple_wml::document*>::iterator i = history_.begin(); i != history_.end(); ++i) {
00077         delete *i;
00078     }
00079 }
00080 
00081 bool game::allow_observers() const {
00082     return level_["observer"].to_bool(true);
00083 }
00084 
00085 bool game::is_observer(const network::connection player) const {
00086     return std::find(observers_.begin(),observers_.end(),player) != observers_.end();
00087 }
00088 
00089 bool game::is_muted_observer(const network::connection player) const {
00090     if (is_observer(player)) {
00091         if (all_observers_muted_) return true;
00092     } else {
00093         return false;
00094     }
00095     return std::find(muted_observers_.begin(), muted_observers_.end(), player)
00096         != muted_observers_.end();
00097 }
00098 
00099 bool game::is_player(const network::connection player) const {
00100     return std::find(players_.begin(),players_.end(),player) != players_.end();
00101 }
00102 
00103 namespace {
00104 std::string describe_turns(int turn, const simple_wml::string_span& num_turns)
00105 {
00106     char buf[50];
00107     snprintf(buf,sizeof(buf),"%d/",int(turn));
00108 
00109     if(num_turns == "-1") {
00110         return buf + std::string("-");
00111     } else {
00112         return buf + std::string(num_turns.begin(), num_turns.end());
00113     }
00114 }
00115 
00116 }//anon namespace
00117 
00118 void game::start_game(const player_map::const_iterator starter) {
00119     // If the game was already started we're actually advancing.
00120     const bool advance = started_;
00121     started_ = true;
00122     // Prevent inserting empty keys when reading.
00123     const simple_wml::node& s = level_.root();
00124     const bool save = s["savegame"].to_bool();
00125     LOG_GAME << network::ip_address(starter->first) << "\t"
00126         << starter->second.name() << "\t" << (advance ? "advanced" : "started")
00127         << (save ? " reloaded" : "") << " game:\t\"" << name_ << "\" (" << id_
00128         << "). Settings: map: " << s["id"]
00129         << "\tera: "       << (s.child("era") ? (*s.child("era"))["id"] : "")
00130         << "\tXP: "        << s["experience_modifier"]
00131         << "\tGPV: "       << s["mp_village_gold"]
00132         << "\tfog: "       << s["mp_fog"]
00133         << "\tshroud: "    << s["mp_shroud"]
00134         << "\tobservers: " << s["observer"]
00135         << "\ttimer: "     << s["mp_countdown"]
00136         << (s["mp_countdown"].to_bool() ?
00137             "\treservoir time: " + s["mp_countdown_reservoir_time"].to_string() +
00138             "\tinit time: "      + s["mp_countdown_init_time"].to_string() +
00139             "\taction bonus: "   + s["mp_countdown_action_bonus"].to_string() +
00140             "\tturn bonus: "     + s["mp_countdown_turn_bonus"].to_string() : "")
00141         << "\n";
00142 
00143     nsides_ = 0;
00144     // Set all side controllers to 'human' so that observers will understand
00145     // that they can't take control of any sides if they happen to have the
00146     // same name as one of the descriptions.
00147     const simple_wml::node::child_list& sides = level_.root().children("side");
00148     for(simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
00149         nsides_++;
00150         if((**s)["controller"] != "null" && !advance) {
00151             (*s)->set_attr("controller", "human");
00152         }
00153     }
00154 
00155     DBG_GAME << "Number of sides: " << nsides_ << "\n";
00156     int turn = 1;
00157     int side = 0;
00158     // Savegames have a snapshot that tells us which side starts.
00159     if (s.child("snapshot")) {
00160         turn = lexical_cast_default<int>((*s.child("snapshot"))["turn_at"], 1);
00161         side = lexical_cast_default<int>((*s.child("snapshot"))["playing_team"], 0);
00162         LOG_GAME << "Reload from turn: " << turn
00163             << ". Current side is: " << side + 1 << ".\n";
00164     }
00165     end_turn_ = (turn - 1) * nsides_ + side - 1;
00166     end_turn();
00167     history_.clear();
00168     if (advance) {
00169         // Re-assign sides to allow correct filtering of commands.
00170         update_side_data();
00171         // When the host advances tell everyone that the next scenario data is
00172         // available.
00173         static simple_wml::document notify_next_scenario("[notify_next_scenario]\n[/notify_next_scenario]\n", simple_wml::INIT_COMPRESSED);
00174         send_data(notify_next_scenario, starter->first);
00175     }
00176     // Send [observer] tags for all observers that are already in the game.
00177     send_observerjoins();
00178 }
00179 
00180 //! Figures out which side to take and tells that side to the game owner.
00181 //! The owner then should send a [scenario_diff] that implements the side
00182 //! change and a subsequent update_side_data() call makes it actually
00183 //! happen.
00184 //! First we look for a side where save_id= or current_player= matches the
00185 //! new user's name then we search for the first controller="network" side.
00186 bool game::take_side(const player_map::const_iterator user)
00187 {
00188     DBG_GAME << "take_side...\n";
00189     DBG_GAME << debug_player_info();
00190 
00191     if (started_) return false;
00192 
00193     simple_wml::document cfg;
00194     cfg.root().set_attr_dup("name", user->second.name().c_str());
00195     cfg.root().set_attr("faction", "random");
00196     cfg.root().set_attr("leader", "random");
00197     cfg.root().set_attr("gender", "random");
00198 
00199     size_t side_num;
00200     // Check if we can figure out a fitting side.
00201     const simple_wml::node::child_list& sides = level_.root().children("side");
00202     for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
00203         if((**side)["controller"] == "network"
00204                 && ((**side)["save_id"] == user->second.name().c_str()
00205                 || (**side)["current_player"] == user->second.name().c_str()))
00206         {
00207             side_num = (**side)["side"].to_int();
00208             if (side_num < 1 || side_num > gamemap::MAX_PLAYERS) continue;
00209             if (sides_taken_[side_num - 1]) continue;
00210             side_controllers_[side_num - 1] = "network";
00211             sides_[side_num - 1] = user->first;
00212             sides_taken_[side_num - 1] = true;
00213             cfg.root().set_attr_dup("side", (**side)["side"]);
00214             // Tell the host which side the new player should take.
00215             
00216             simple_wml::string_span data = cfg.output_compressed();
00217             network::send_raw_data(data.begin(), data.size(), owner_);
00218             DBG_GAME << "take_side: took side " << side_num << " because the name matched\n";
00219             DBG_GAME << debug_player_info();
00220             return true;
00221         }
00222     }
00223     // If there was no fitting side just take the first available.
00224     for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
00225         if((**side)["controller"] == "network") {
00226             //don't allow players to take sides in games with invalid side numbers
00227             try {
00228                 side_num = (**side)["side"].to_int();
00229             } catch (bad_lexical_cast&) { continue; }
00230             if (side_num < 1 || side_num > gamemap::MAX_PLAYERS) continue;
00231             if (sides_taken_[side_num - 1]) continue;
00232             // we expect that the host will really use our proposed side number (he could do different)
00233             side_controllers_[side_num - 1] = "network";
00234             sides_[side_num - 1] = user->first;
00235             sides_taken_[side_num - 1] = true;
00236             cfg.root().set_attr_dup("side", (**side)["side"]);
00237             // Tell the host which side the new player should take.
00238             simple_wml::string_span data = cfg.output_compressed();
00239             network::send_raw_data(data.begin(), data.size(), owner_);
00240             DBG_GAME << "take_side: took the first free network side which was " << side_num << "\n";
00241             DBG_GAME << debug_player_info();
00242             return true;
00243         }
00244     }
00245     DBG_GAME << "take_side: there are no more sides available\n";
00246     //if we get here we couldn't find a side to take
00247     return false;
00248 }
00249 
00250 //! Resets the side configuration according to the scenario data.
00251 void game::update_side_data() {
00252     DBG_GAME << "update_side_data...\n";
00253     DBG_GAME << debug_player_info();
00254     // Remember everyone that is in the game.
00255     const user_vector users = all_game_users();
00256 
00257     side_controllers_.clear();
00258     side_controllers_.resize(gamemap::MAX_PLAYERS);
00259     sides_taken_.clear();
00260     // Resize because we assume a default of 'false' for all sides later.
00261     sides_taken_.resize(gamemap::MAX_PLAYERS);
00262     sides_.clear();
00263     sides_.resize(gamemap::MAX_PLAYERS);
00264     players_.clear();
00265     observers_.clear();
00266 
00267     const simple_wml::node::child_list& level_sides = level_.root().children("side");
00268 /*  for (config::child_iterator side = level_sides.first;
00269             side != level_sides.second; ++side)
00270         DBG_GAME << (**side);*/
00271     // For each user:
00272     // * Find the username.
00273     // * Find the side this username corresponds to.
00274     for (user_vector::const_iterator user = users.begin(); user != users.end(); ++user) {
00275         const player_map::const_iterator info = player_info_->find(*user);
00276         if (info == player_info_->end()) {
00277             ERR_GAME << "Game: " << id_
00278                 << " ERROR: unable to find user info for connection: "
00279                 << *user << "\n";
00280             continue;
00281         }
00282 
00283         bool side_found = false;
00284         for (simple_wml::node::child_list::const_iterator side = level_sides.begin();
00285                 side != level_sides.end(); ++side)
00286         {
00287             size_t side_num = (**side)["side"].to_int();
00288             if (side_num < 1 || side_num > gamemap::MAX_PLAYERS
00289                     || sides_taken_[side_num - 1]) continue;
00290 
00291             if ((**side)["controller"] == "network") {
00292                 side_controllers_[side_num - 1] = "network";
00293                 if ((**side)["current_player"] == info->second.name().c_str()) {
00294                     sides_[side_num - 1] = *user;
00295                     sides_taken_[side_num - 1] = true;
00296                     side_found = true;
00297                 } else sides_taken_[side_num - 1] = false;
00298             } else if ((**side)["controller"] == "ai") {
00299                 side_controllers_[side_num - 1] = "ai";
00300                 sides_[side_num - 1] = owner_;
00301                 sides_taken_[side_num - 1] = true;
00302                 side_found = true;
00303             } else if ((**side)["controller"] == "human") {
00304                 side_controllers_[side_num - 1] = "human";
00305                 sides_[side_num - 1] = owner_;
00306                 sides_taken_[side_num - 1] = true;
00307                 side_found = true;
00308             } else if ((**side)["controller"] == "null") {
00309                 side_controllers_[side_num - 1] = "null";
00310             }
00311         }
00312         if (side_found) {
00313             players_.push_back(*user);
00314         } else {
00315             observers_.push_back(*user);
00316         }
00317     }
00318     DBG_GAME << debug_player_info();
00319 }
00320 
00321 void game::transfer_side_control(const network::connection sock, const simple_wml::node& cfg) {
00322     DBG_GAME << "transfer_side_control...\n";
00323     if (!is_player(sock) && sock != owner_) {
00324         send_server_message("You cannot change controllers: not a player.", sock);
00325         return;
00326     }
00327 
00328     //check, if this socket belongs to a player
00329     const user_vector::iterator pl = std::find(players_.begin(), players_.end(), sock);
00330     if (pl == players_.end()) {
00331         ERR_GAME << "ERROR: Not a player of this game. (socket: " << sock << ")\n";
00332         return;
00333     }
00334     const simple_wml::string_span& newplayer_name = cfg["player"];
00335     //find the player that is passed control
00336     player_map::const_iterator newplayer;
00337     for (newplayer = player_info_->begin(); newplayer != player_info_->end(); newplayer++) {
00338         if (newplayer_name == newplayer->second.name().c_str()) {
00339             break;
00340         }
00341     }
00342     // Is he in this game?
00343     if (newplayer == player_info_->end() || !is_member(newplayer->first)) {
00344         send_server_message("Player/Observer not in this game", sock);
00345         return;
00346     }
00347     // Check the side number.
00348     const unsigned int side_num = cfg["side"].to_int();
00349     if(side_num < 1 || side_num > gamemap::MAX_PLAYERS) {
00350         std::ostringstream msg;
00351         msg << "The side number has to be between 1 and " 
00352             << gamemap::MAX_PLAYERS << ".";
00353         send_server_message(msg.str().c_str(), sock);
00354         return;
00355     }
00356 
00357     if (side_num > level_.root().children("side").size()) {
00358         send_server_message("Invalid side number.", sock);
00359         return;
00360     }
00361 
00362     network::connection old_player = sides_[side_num - 1];
00363     const std::string old_player_name =
00364             (player_info_->find(old_player) != player_info_->end()
00365             ? player_info_->find(old_player)->second.name() : "");
00366     // Check if the sender actually owns the side he gives away or is the host.
00367     if (sock != old_player && sock != owner_) {
00368         std::stringstream msg;
00369         msg << "You can't give away side " << side_num << ". It's controlled by '"
00370             << old_player_name << "' not you.";
00371         DBG_GAME << msg.str() << "\n";
00372         send_server_message(msg.str().c_str(), sock);
00373         return;
00374     }
00375     if (newplayer->first == old_player) {
00376         std::stringstream msg;
00377         msg << "That's already " << newplayer_name << "'s side, silly.";
00378         send_server_message(msg.str().c_str(), sock);
00379         return;
00380     }
00381     sides_[side_num - 1] = 0;
00382     bool host_leave = false;
00383     // If the old player lost his last side, make him an observer.
00384     if (std::find(sides_.begin(), sides_.end(), old_player) == sides_.end()) {
00385         observers_.push_back(old_player);
00386         players_.erase(std::remove(players_.begin(), players_.end(), old_player), players_.end());
00387         // Tell others that the player becomes an observer.
00388         send_and_record_server_message((old_player_name + " becomes an observer.").c_str());
00389         // Update the client side observer list for everyone except old player.
00390         simple_wml::document observer_join;
00391         observer_join.root().add_child("observer").set_attr_dup("name", old_player_name.c_str());
00392         send_data(observer_join, old_player);
00393         // If the old player was the host of the game, choose another player.
00394         /*if (old_player == owner_) {
00395             host_leave = true;
00396             if (players_.empty()) {
00397                 owner_ = newplayer->first;
00398             } else {
00399                 owner_ = players_.front();
00400             }
00401             notify_new_host();
00402         }*/
00403     }
00404     side_controllers_[side_num - 1] = "network";
00405     sides_taken_[side_num - 1] = true;
00406     sides_[side_num - 1] = newplayer->first;
00407 
00408     send_change_controller(side_num, newplayer, false);
00409     if (host_leave) transfer_ai_sides();
00410 
00411     // If we gave the new side to an observer add him to players_.
00412     if (is_observer(newplayer->first)) {
00413         players_.push_back(newplayer->first);
00414         observers_.erase(std::remove(observers_.begin(), observers_.end(), newplayer->first), observers_.end());
00415         // Send everyone but the new player the observer_quit message.
00416         send_observerquit(newplayer);
00417     }
00418 }
00419 
00420 //! Send [change_controller] message to tell all clients the new controller's name.
00421 void game::send_change_controller(const size_t side_num,
00422         const player_map::const_iterator newplayer, const bool player_left)
00423 {
00424     if (newplayer == player_info_->end()) {
00425         return;
00426     }
00427 
00428     const std::string& side = lexical_cast<std::string, size_t>(side_num);
00429     if (started_) {
00430         send_and_record_server_message((newplayer->second.name()
00431                 + " takes control of side " + side + ".").c_str());
00432     }
00433 
00434     simple_wml::document response;
00435     simple_wml::node& change = response.root().add_child("change_controller");
00436 
00437     change.set_attr("side", side.c_str());
00438     change.set_attr("player", newplayer->second.name().c_str());
00439 
00440     // Tell everyone but the new player that this side is network controlled now.
00441     change.set_attr("controller", "network");
00442     send_data(response, newplayer->first);
00443 
00444     // Tell the new player that he controls this side now.
00445     // Just don't send it when the player left the game. (The host gets the
00446     // side_drop already.)
00447     if (!player_left) {
00448         change.set_attr("controller", "human");
00449         send_to_one(response, newplayer->first);
00450     }
00451 
00452     // Update the level so observers who join get the new name.
00453     const simple_wml::node::child_list& side_list = level_.root().children("side");
00454     const unsigned int index = side_num - 1;
00455     assert(index < side_list.size());
00456     side_list[index]->set_attr_dup("current_player", newplayer->second.name().c_str());
00457 }
00458 
00459 void game::transfer_ai_sides() {
00460     bool ai_transfer = false;
00461     // Check for ai sides first and drop them, too, if the host left.
00462     for (size_t side = 0; side < side_controllers_.size(); ++side){
00463         //send the host a notification of removal of this side
00464         if (side_controllers_[side] != "ai") continue;
00465 
00466         ai_transfer = true;
00467         simple_wml::document drop;
00468         const std::string side_drop = lexical_cast<std::string, size_t>(side + 1);
00469         drop.root().set_attr("side_drop", side_drop.c_str());
00470         drop.root().set_attr("controller", "ai");
00471         const simple_wml::string_span data = drop.output_compressed();
00472         network::send_raw_data(data.begin(), data.size(), owner_);
00473         sides_[side] = owner_;
00474     }
00475     if (ai_transfer) {
00476         send_and_record_server_message("AI sides transferred to new host.");
00477     }
00478 }
00479 
00480 void game::notify_new_host(){
00481     const std::string owner_name =
00482             (player_info_->find(owner_) != player_info_->end()
00483             ? player_info_->find(owner_)->second.name() : "");
00484     simple_wml::document cfg;
00485     simple_wml::node& cfg_host_transfer = cfg.root().add_child("host_transfer");
00486 
00487     // Why do we send the new host his own name?
00488     cfg_host_transfer.set_attr("name", owner_name.c_str());
00489     cfg_host_transfer.set_attr("value", "1");
00490     const simple_wml::string_span data = cfg.output_compressed();
00491     network::send_raw_data(data.begin(), data.size(), owner_);
00492     send_and_record_server_message((owner_name
00493             + " has been chosen as the new host.").c_str());
00494 }
00495 
00496 bool game::describe_slots() {
00497     if(started_ || description_ == NULL)
00498         return false;
00499 
00500     int available_slots = 0;
00501     int num_sides = level_.root().children("side").size();
00502     int i = 0;
00503     const simple_wml::node::child_list& side_list = level_.root().children("side");
00504     for(simple_wml::node::child_list::const_iterator it = side_list.begin(); it != side_list.end(); ++it, ++i) {
00505         if (((**it)["allow_player"].to_bool(true) == false) || (**it)["controller"] == "null") {
00506             num_sides--;
00507         } else {
00508             if (!sides_taken_[i])
00509                 available_slots++;
00510         }
00511     }
00512     char buf[50];
00513     snprintf(buf,sizeof(buf), "%d/%d", available_slots, num_sides);
00514 
00515     if ((*description_)["slots"] != buf) {
00516         description_->set_attr_dup("slots", buf);
00517         return true;
00518     } else {
00519         return false;
00520     }
00521 }
00522 
00523 //! Checks whether the connection's ip address is banned.
00524 bool game::player_is_banned(const network::connection sock) const {
00525     std::vector<std::string>::const_iterator ban =
00526         std::find(bans_.begin(), bans_.end(), network::ip_address(sock));
00527     return ban != bans_.end();
00528 }
00529 
00530 void game::mute_all_observers() {
00531     all_observers_muted_ = !all_observers_muted_;
00532     if (all_observers_muted_) {
00533         send_and_record_server_message("All observers have been muted.");
00534     } else {
00535         send_and_record_server_message("Muting of all observers has been removed.");
00536     }
00537 }
00538 
00539 //! Mute an observer or give a message of all currently muted observers if no
00540 //! name is given.
00541 void game::mute_observer(const simple_wml::node& mute, const player_map::const_iterator muter) {
00542     if (muter->first != owner_) {
00543         send_server_message("You cannot mute: not the game host.", muter->first);
00544         return;
00545     }
00546     const simple_wml::string_span& name = mute["username"];
00547     if (name.empty()) {
00548         if (all_observers_muted_) {
00549             send_server_message("All observers are muted.", muter->first);
00550             return;
00551         }
00552         std::string muted_nicks = "";
00553         for (user_vector::const_iterator muted_obs = muted_observers_.begin();
00554              muted_obs != muted_observers_.end(); ++muted_obs)
00555         {
00556             if (muted_nicks != "") {
00557                 muted_nicks += ", ";
00558             }
00559             muted_nicks += player_info_->find(*muted_obs)->second.name();
00560         }
00561 
00562         send_server_message(("Muted observers: " + muted_nicks).c_str(), muter->first);
00563         return;
00564     }
00565     const player_map::const_iterator user = find_user(name);
00566     //! @todo FIXME: Maybe rather save muted nicks as a vector of strings
00567     //! and also allow muting of usernames not in the game.
00568     if (user == player_info_->end() || !is_observer(user->first)) {
00569         send_server_message("Observer not found.", muter->first);
00570         return;
00571     }
00572     //! Prevent muting ourselves.
00573     if (user->first == muter->first) {
00574         send_server_message("Don't mute yourself, silly.", muter->first);
00575         return;
00576     }
00577     if (is_muted_observer(user->first)) {
00578         send_server_message((user->second.name() + " is already muted.").c_str(), muter->first);
00579         return;
00580     }
00581     muted_observers_.push_back(user->first);
00582     LOG_GAME << network::ip_address(muter->first) << "\t"
00583         << muter->second.name() << " muted: " << user->second.name()
00584         << "\tfrom game:\t\"" << name_ << "\" (" << id_ << ")\n";
00585     send_and_record_server_message((user->second.name() + " has been muted.").c_str());
00586 }
00587 
00588 //! Kick a member by name.
00589 //! @return the network handle of the removed member if successful, '0' otherwise.
00590 network::connection game::kick_member(const simple_wml::node& kick, 
00591         const player_map::const_iterator kicker)
00592 {
00593     if (kicker->first != owner_) {
00594         send_server_message("You cannot kick: not the game host", kicker->first);
00595         return 0;
00596     }
00597     const simple_wml::string_span& name = kick["username"];
00598     const player_map::const_iterator user = find_user(name);
00599     if (user == player_info_->end() || !is_member(user->first)) {
00600         send_server_message("Not a member of this game.", kicker->first);
00601         return 0;
00602     }
00603     if (user->first == kicker->first) {
00604         send_server_message("Don't kick yourself, silly.", kicker->first);
00605         return 0;
00606     }
00607     LOG_GAME << network::ip_address(kicker->first) << "\t"
00608         << kicker->second.name() << "\tkicked: " << user->second.name()
00609         << "\tfrom game:\t\"" << name_ << "\" (" << id_ << ")\n";
00610     send_and_record_server_message((name.to_string() + " has been kicked.").c_str());
00611 
00612     // Tell the user to leave the game.
00613     static simple_wml::document leave_game("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
00614     static const simple_wml::string_span leave_game_data = leave_game.output_compressed();
00615     network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first);
00616     remove_player(user->first);
00617     return user->first;
00618 }
00619 
00620 //! Ban a user by name.
00621 //! The user does not need to be in this game but logged in.
00622 //! @return the network handle of the banned player if he was in this game, '0'
00623 //! otherwise.
00624 network::connection game::ban_user(const simple_wml::node& ban,
00625         const player_map::const_iterator banner)
00626 {
00627     if (banner->first != owner_) {
00628         send_server_message("You cannot ban: not the game host", banner->first);
00629         return 0;
00630     }
00631     const simple_wml::string_span& name = ban["username"];
00632     const player_map::const_iterator user = find_user(name);
00633     if (user == player_info_->end()) {
00634         send_server_message("User not found", banner->first);
00635         return 0;
00636     }
00637     if (user->first == banner->first) {
00638         send_server_message("Don't ban yourself, silly.", banner->first);
00639         return 0;
00640     }
00641     if (player_is_banned(user->first)) {
00642         std::ostringstream stream;
00643         stream << name << " is already banned.";
00644         send_server_message(stream.str().c_str(), banner->first);
00645         return 0;
00646     }
00647     LOG_GAME << network::ip_address(banner->first) << "\t"
00648         << banner->second.name() << "\tbanned: " << name << "\tfrom game:\t"
00649         << name_ << "\" (" << id_ << ")\n";
00650     bans_.push_back(network::ip_address(user->first));
00651     send_and_record_server_message((name.to_string() + " has been banned.").c_str());
00652     if (is_member(user->first)) {
00653         //tell the user to leave the game.
00654         static simple_wml::document leave_game("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
00655         static const simple_wml::string_span leave_game_data = leave_game.output_compressed();
00656         network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first);
00657         remove_player(user->first);
00658         return user->first;
00659     }
00660     // Don't return the user if he wasn't in this game.
00661     return 0;
00662 }
00663 
00664 void game::process_message(simple_wml::document& data, const player_map::iterator user) {
00665     // Hack to handle the pseudo game lobby_.
00666     if (owner_ != 0) {
00667     } else if (user->second.silenced()) {
00668         return;
00669     } else if (user->second.is_message_flooding()) {
00670         send_server_message(
00671                 "Warning: you are sending too many messages too fast. "
00672                 "Your message has not been relayed.", user->first);
00673         return;
00674     }
00675 
00676     simple_wml::node* const message = data.root().child("message");
00677     assert(message);
00678     message->set_attr_dup("sender", user->second.name().c_str());
00679     
00680     const simple_wml::string_span& msg = (*message)["message"];
00681     chat_message::truncate_message(msg, *message);
00682 
00683     // Only log in the lobby_.
00684     if (owner_ != 0) {
00685     } else if (msg.size() >= 3 && simple_wml::string_span(msg.begin(), 4) == "/me ") {
00686         LOG_GAME << network::ip_address(user->first) << "\t<"
00687             << user->second.name() << simple_wml::string_span(msg.begin() + 3, msg.size() - 3) << ">\n";
00688         } else {
00689         LOG_GAME << network::ip_address(user->first) << "\t<"
00690             << user->second.name() << "> " << msg << "\n";
00691     }
00692 
00693     send_data(data, user->first);
00694 }
00695 
00696 bool game::is_legal_command(const simple_wml::node& command, bool is_player) {
00697     // Only single commands allowed.
00698     if (!command.one_child()) return false;
00699     // Chatting is never an illegal command.
00700     if (command.child("speak")) return true;
00701     if (is_player
00702     && (command.child("label")
00703         || command.child("clear_labels")
00704         || command.child("rename")
00705         || command.child("countdown_update")
00706         || command.child("advance_unit")
00707         || command.child("choose")))
00708     {
00709         return true;
00710     }
00711     return false;
00712 }
00713 
00714 //! Handles [end_turn], repackages [commands] with private [speak]s in them
00715 //! and sends the data.
00716 //! Also filters commands from all but the current player.
00717 //! Currently removes all commands but [speak] for observers and all but
00718 //! [speak], [label] and [rename] for players.
00719 //! Returns true if the turn ended.
00720 bool game::process_turn(simple_wml::document& data, const player_map::const_iterator user) {
00721     //DBG_GAME << "processing commands: '" << cfg << "'\n";
00722     if (!started_) return false;
00723     simple_wml::node* const turn = data.root().child("turn");
00724     bool turn_ended = false;
00725     // Any private 'speak' commands must be repackaged separate
00726     // to other commands, and re-sent, since they should only go
00727     // to some clients.
00728     bool repackage = false;
00729     int index = 0;
00730     std::vector<int> marked;
00731     const simple_wml::node::child_list& commands = turn->children("command");
00732     simple_wml::node::child_list::const_iterator command;
00733     for (command = commands.begin(); command != commands.end(); ++command) {
00734         if (!is_current_player(user->first)
00735         && !is_legal_command(**command, is_player(user->first))) {
00736             std::cerr << "ILLEGAL COMMAND: (((" << data.output() << ")))\n";
00737             std::stringstream msg;
00738             msg << "Removing illegal command from: " << user->second.name()
00739                 << ". Current player is: "
00740                 << (player_info_->find(current_player()) != player_info_->end()
00741                     ? player_info_->find(current_player())->second.name()
00742                     : "(unfound) ")// << nsides_ << "/" << end_turn_
00743                 << ".\n";
00744             LOG_GAME << msg.str();
00745             send_and_record_server_message(msg.str().c_str());
00746             //TODO: make an easy way to convert a simple wml node to a string
00747             //LOG_GAME << (**command).output();
00748             marked.push_back(index - marked.size());
00749         } else if ((**command).child("speak")) {
00750             simple_wml::node& speak = *(**command).child("speak");
00751             if (!(speak["team_name"] == "")
00752             || (is_muted_observer(user->first))) {
00753                 repackage = true;
00754             }
00755 
00756             const simple_wml::string_span& msg = speak["message"];
00757             chat_message::truncate_message(msg, speak);
00758 
00759             // Force the description to be correct,
00760             // to prevent spoofing of messages.
00761             speak.set_attr_dup("id", user->second.name().c_str());
00762             // Also check the side for players.
00763             if (is_player(user->first)) {
00764                 const size_t side_num = speak["side"].to_int();
00765                 if (side_num < 1 || side_num > gamemap::MAX_PLAYERS
00766                 || sides_[side_num - 1] != user->first) {
00767                     if (user->first == current_player()) {
00768                         speak.set_attr_dup("side", lexical_cast<std::string>(current_side() + 1).c_str());
00769                     } else {
00770                         const side_vector::const_iterator s =
00771                                 std::find(sides_.begin(), sides_.end(), user->first);
00772                         speak.set_attr_dup("side", lexical_cast<std::string>(s - sides_.begin() + 1).c_str());
00773                     }
00774                 }
00775             }
00776         } else if (is_current_player(user->first) && (**command).child("end_turn")) {
00777             turn_ended = end_turn();
00778         }
00779         ++index;
00780     }
00781     for(std::vector<int>::const_iterator j = marked.begin(); j != marked.end(); ++j) {
00782         turn->remove_child("command",*j);
00783     }
00784     if (turn->no_children()) {
00785         return false;
00786     }
00787     if (!repackage) {
00788         record_data(data.clone());
00789         send_data(data, user->first);
00790         return turn_ended;
00791     }
00792     for (command = commands.begin(); command != commands.end(); ++command) {
00793         simple_wml::node* const speak = (**command).child("speak");
00794         if (speak == NULL) {
00795             simple_wml::document* mdata = new simple_wml::document;
00796             simple_wml::node& turn = mdata->root().add_child("turn");
00797             (**command).copy_into(turn.add_child("command"));
00798             send_data(*mdata, user->first);
00799             record_data(mdata);
00800             continue;
00801         }
00802         const simple_wml::string_span& team_name = (*speak)["team_name"];
00803         // Anyone can send to the observer team.
00804         if (team_name == game_config::observer_team_name.c_str()) {
00805         // Don't send if the member is muted.
00806         } else if (is_muted_observer(user->first)) {
00807             send_server_message("You have been muted, others can't see your message!", user->first);
00808             continue;
00809         // Don't send if the player addresses a different team.
00810         } else if (!is_on_team(team_name, user->first)) {
00811             std::ostringstream msg;
00812             msg << "Removing illegal message from " << user->second.name() << " to " << std::string(team_name.begin(), team_name.end()) << ".";
00813             const std::string& msg_str = msg.str();
00814             LOG_GAME << msg_str << std::endl;
00815             send_and_record_server_message(msg_str.c_str());
00816             continue;
00817         }
00818 
00819         std::auto_ptr<simple_wml::document> message(new simple_wml::document);
00820         simple_wml::node& turn = message->root().add_child("turn");
00821         simple_wml::node& command = turn.add_child("command");
00822         speak->copy_into(command.add_child("speak"));
00823         if (team_name == "") {
00824             send_data(*message, user->first);
00825             record_data(message.release());
00826         } else if (team_name == game_config::observer_team_name) {
00827             send_data_observers(*message, user->first);
00828             record_data(message.release());
00829         } else {
00830             send_data_team(*message, team_name, user->first);
00831         }
00832     }
00833     return turn_ended;
00834 }
00835 
00836 bool game::end_turn() {
00837     // It's a new turn every time each side in the game ends their turn.
00838     ++end_turn_;
00839     bool turn_ended = false;
00840     if ((current_side()) == 0) {
00841         turn_ended = true;
00842     }
00843     // Skip over empty sides.
00844     for (int i = 0; i < nsides_ && nsides_ <= gamemap::MAX_PLAYERS && side_controllers_[current_side()] == "null"; ++i) {
00845         ++end_turn_;
00846         if (current_side() == 0) {
00847             turn_ended = true;
00848         }
00849     }
00850     if (!turn_ended) return false;
00851 
00852     if (description_ == NULL) {
00853         return false;
00854     }
00855 
00856     description_->set_attr_dup("turn", describe_turns(current_turn(), level_["turns"]).c_str());
00857 
00858     return true;
00859 }
00860 
00861 void game::add_player(const network::connection player, bool observer) {
00862     if(is_member(player)) {
00863         ERR_GAME << "ERROR: Player is already in this game. (socket: "
00864             << player << ")\n";
00865         return;
00866     }
00867     // Hack to handle the pseudo games lobby_ and not_logged_in_.
00868     if (owner_ == 0) {
00869         observers_.push_back(player);
00870         return;
00871     }
00872     const player_map::iterator user = player_info_->find(player);
00873     if (user == player_info_->end()) {
00874         ERR_GAME << "ERROR: Could not find user in player_info_. (socket: "
00875             << owner_ << ")\n";
00876         return;
00877     }
00878     user->second.mark_available(id_, name_);
00879     DBG_GAME << debug_player_info();
00880     bool became_observer = false;
00881     if (!started_ && !observer && take_side(user)) {
00882         DBG_GAME << "adding player...\n";
00883         players_.push_back(player);
00884         send_server_message((user->second.name()
00885                 + " has joined the game.").c_str(), player);
00886     } else if (!allow_observers()) {
00887         return; //false;
00888     } else {
00889         if (!observer) became_observer = true;
00890         DBG_GAME << "adding observer...\n";
00891         observers_.push_back(player);
00892 
00893         simple_wml::document observer_join;
00894         observer_join.root().add_child("observer").set_attr_dup("name", user->second.name().c_str());
00895 
00896         // Send observer join to everyone except the new observer.
00897         send_data(observer_join, player);
00898     }
00899     DBG_GAME << debug_player_info();
00900     // Send the user the game data.
00901     //std::cerr << "SENDING LEVEL {{{" << level_.output() << "}}}\n";
00902     simple_wml::string_span level_data = level_.output_compressed();
00903     network::send_raw_data(level_data.begin(), level_data.size(), player);
00904     if(started_) {
00905         //tell this player that the game has started
00906         static simple_wml::document start_game_doc("[start_game]\n[/start_game]\n", simple_wml::INIT_COMPRESSED);
00907         static const simple_wml::string_span start_game = start_game_doc.output_compressed();
00908         network::send_raw_data(start_game.begin(), start_game.size(), player);
00909         // Send observer join of all the observers in the game to the new player
00910         // only once the game started. The client forgets about it anyway
00911         // otherwise.
00912         send_observerjoins(player);
00913         // Send the player the history of the game to-date.
00914         send_history(player);
00915     } else {
00916         send_user_list();
00917     }
00918 
00919     if (became_observer) {
00920         // in case someone took the last slot right before this player
00921         send_server_message("You are an observer.", player);
00922     }
00923 }
00924 
00925 //! Removes a user from the game.
00926 //! @return true iff the game ends that is if there are no more players
00927 //! or the host left on a not yet started game.
00928 bool game::remove_player(const network::connection player, const bool disconnect) {
00929     if (!is_member(player)) {
00930         ERR_GAME << "ERROR: User is not in this game. (socket: "
00931             << player << ")\n";
00932         return false;
00933     }
00934     // Hack to handle the pseudo games lobby_ and not_logged_in_.
00935     if (owner_ == 0) {
00936         const user_vector::iterator itor =
00937             std::find(observers_.begin(), observers_.end(), player);
00938         if (itor != observers_.end()) {
00939             observers_.erase(itor);
00940         } else {
00941             ERR_GAME << "ERROR: Observer is not in this game. (socket: "
00942                 << player << ")\n";
00943         }
00944         return false;
00945     }
00946     DBG_GAME << debug_player_info();
00947     DBG_GAME << "removing player...\n";
00948 
00949     const bool host = (player == owner_);
00950     const bool observer = is_observer(player);
00951     players_.erase(std::remove(players_.begin(), players_.end(), player), players_.end());
00952     observers_.erase(std::remove(observers_.begin(), observers_.end(), player), observers_.end());
00953     const bool game_ended = (players_.empty() || (host && !started_));
00954     const player_map::iterator user = player_info_->find(player);
00955     if (user == player_info_->end()) {
00956         ERR_GAME << "ERROR: Could not find user in player_info_. (socket: "
00957             << player << ")\n";
00958         return false;
00959     }
00960     LOG_GAME << network::ip_address(user->first) << "\t" << user->second.name()
00961         << (game_ended ? (started_ ? "\tended" : "\taborted") : "\thas left")
00962         << " game:\t\"" << name_ << "\" (" << id_ << ")"
00963         << (game_ended && started_ ? " at turn: "
00964             + lexical_cast_default<std::string,size_t>(current_turn())
00965             + " with reason: '" + termination_reason() + "'" : "")
00966         << (observer ? " as an observer" : "")
00967         << (disconnect ? " and disconnected" : "")
00968         << ". (socket: " << user->first << ")\n";
00969     if (game_ended) {
00970         send_server_message_to_all((user->second.name() + " ended the game.").c_str(), player);
00971         return true;
00972     }
00973     // Don't mark_available() since the player got already removed from the
00974     // games_and_users_list_.
00975     if (!disconnect) user->second.mark_available();
00976     if (observer) {
00977         send_observerquit(user);
00978     } else {
00979         send_and_record_server_message((user->second.name()
00980                 + (disconnect ? " has disconnected." : " has left the game.")).c_str(), player);
00981     }
00982     // If the player was host choose a new one.
00983     if (host) {
00984         owner_ = players_.front();
00985         notify_new_host();
00986     }
00987 
00988     // Look for all sides the player controlled and drop them.
00989     // (Give them to the host.)
00990     for (side_vector::iterator side = sides_.begin(); side != sides_.end(); ++side) {
00991         if (*side != player) continue;
00992         size_t side_num = side - sides_.begin();
00993         side_controllers_[side_num] = "human";
00994         sides_taken_[side_num] = true;
00995         sides_[side_num] = owner_;
00996         // Check whether the host is actually a player and make him one if not.
00997         if (!is_player(owner_)) {
00998             DBG_GAME << "making the owner a player...\n";
00999             observers_.erase(std::remove(observers_.begin(), observers_.end(), owner_), observers_.end());
01000             players_.push_back(owner_);
01001             send_observerquit(player_info_->find(owner_));
01002         }
01003         send_change_controller(side_num + 1, player_info_->find(owner_));
01004 
01005         //send the host a notification of removal of this side
01006         char side_drop_buf[64];
01007         sprintf(side_drop_buf, "%d", static_cast<int>(side_num + 1));
01008         simple_wml::document drop;
01009         drop.root().set_attr("side_drop", side_drop_buf);
01010         drop.root().set_attr("controller", side_controllers_[side_num].c_str());
01011 
01012         send_to_one(drop, owner_);
01013     }
01014     if (host) transfer_ai_sides();
01015     DBG_GAME << debug_player_info();
01016 
01017     send_user_list(player);
01018     return false;
01019 }
01020 
01021 void game::send_user_list(const network::connection exclude) const {
01022     //if the game hasn't started yet, then send all players a list
01023     //of the users in the game
01024     if (started_ || description_ == NULL) return;
01025     //! @todo Should be renamed to userlist.
01026     simple_wml::document cfg;
01027     cfg.root().add_child("gamelist");
01028     user_vector users = all_game_users();
01029     for(user_vector::const_iterator p = users.begin(); p != users.end(); ++p) {
01030         const player_map::const_iterator pl = player_info_->find(*p);
01031         if (pl != player_info_->end()) {
01032             //don't need to duplicate pl->second.name().c_str() because the
01033             //document will be destroyed by the end of the function
01034             cfg.root().add_child("user").set_attr("name", pl->second.name().c_str());
01035         }
01036     }
01037     send_data(cfg, exclude);
01038 }
01039 
01040 //! A member asks for the next scenario to advance to.
01041 void game::load_next_scenario(const player_map::const_iterator user) const {
01042     send_server_message_to_all((user->second.name() + " advances to the next scenario").c_str(), user->first);
01043     simple_wml::document cfg_scenario;
01044     level_.root().copy_into(cfg_scenario.root().add_child("next_scenario"));
01045     simple_wml::string_span data = cfg_scenario.output_compressed();
01046     network::send_raw_data(data.begin(), data.size(), user->first);
01047     // Send the player the history of the game to-date.
01048     send_history(user->first);
01049     // Send observer join of all the observers in the game to the user.
01050     send_observerjoins(user->first);
01051 }
01052 
01053 void game::send_data(simple_wml::document& data, const network::connection exclude) const
01054 {
01055     simple_wml::string_span s = data.output_compressed();
01056     const user_vector& users = all_game_users();
01057     for(user_vector::const_iterator i = users.begin(); i != users.end(); ++i) {
01058         if (*i != exclude) {
01059             network::send_raw_data(s.begin(), s.size(), *i);
01060         }
01061     }
01062 }
01063 
01064 void game::send_to_one(simple_wml::document& data, const network::connection sock) const
01065 {
01066     simple_wml::string_span s = data.output_compressed();
01067     network::send_raw_data(s.begin(), s.size(), sock);
01068 }
01069 
01070 void game::send_data_team(simple_wml::document& data,
01071                           const simple_wml::string_span& team,
01072                           const network::connection exclude) const
01073 {
01074     simple_wml::string_span s = data.output_compressed();
01075     for(user_vector::const_iterator i = players_.begin(); i != players_.end(); ++i) {
01076         if(*i != exclude && is_on_team(team,*i)) {
01077             network::send_raw_data(s.begin(), s.size(), *i);
01078         }
01079     }
01080 }
01081 
01082 void game::send_data_observers(simple_wml::document& data, const network::connection exclude) const {
01083     simple_wml::string_span s = data.output_compressed();
01084     for(user_vector::const_iterator i = observers_.begin(); i != observers_.end(); ++i) {
01085         if (*i != exclude) {
01086             network::send_raw_data(s.begin(), s.size(), *i);
01087         }
01088     }
01089 }
01090 
01091 bool game::is_on_team(const simple_wml::string_span& team, const network::connection player) const {
01092     side_vector::const_iterator side = std::find(sides_.begin(), sides_.end(), player);
01093     if(side == sides_.end()) {
01094         return false;
01095     }
01096     const std::string side_str =
01097         lexical_cast<std::string, size_t>(side - sides_.begin() + 1);
01098     const simple_wml::node::child_list& side_list = level_.root().children("side");
01099     for(simple_wml::node::child_list::const_iterator i = side_list.begin();
01100         i != side_list.end(); ++i) {
01101         if((**i)["side"] == side_str.c_str()) {
01102             return (**i)["team_name"] == team;
01103         }
01104     }
01105 
01106     return false;
01107 }
01108 
01109 //! Send [observer] tags of all the observers in the game to the user or
01110 //! everyone if none given.
01111 void game::send_observerjoins(const network::connection sock) const {
01112     for (user_vector::const_iterator ob = observers_.begin(); ob != observers_.end(); ++ob) {
01113         if (*ob == sock) continue;
01114         const player_map::const_iterator obs = player_info_->find(*ob);
01115         if (obs == player_info_->end()) {
01116             ERR_GAME << "Game: " << id_
01117                 << " ERROR: Can not find observer in player_info_. (socket: "
01118                 << *ob << ")\n";
01119             continue;
01120         }
01121 
01122         simple_wml::document cfg;
01123         cfg.root().add_child("observer").set_attr_dup("name", obs->second.name().c_str());
01124         if (sock == 0) {
01125             // Send to everyone except the observer in question.
01126             send_data(cfg, *ob);
01127         } else {
01128             // Send to the (new) user.
01129             const simple_wml::string_span& data = cfg.output_compressed();
01130             network::send_raw_data(data.begin(), data.size(), sock);
01131         }
01132     }
01133 }
01134 
01135 void game::send_observerquit(const player_map::const_iterator observer) const {
01136     if (observer == player_info_->end()) {
01137         return;
01138     }
01139     simple_wml::document observer_quit;
01140 
01141     //don't need to dup the attribute because this document is
01142     //short-lived.
01143     observer_quit.root().add_child("observer_quit").set_attr("name", observer->second.name().c_str());
01144     send_data(observer_quit, observer->first);
01145 }
01146 
01147 void game::send_history(const network::connection sock) const
01148 {
01149     if(history_.empty()) {
01150         return;
01151     }
01152 
01153     //we make a new document based on converting to plain text and
01154     //concatenating the buffers.
01155     //TODO: Work out how to concentate buffers without decompressing.
01156     std::string buf;
01157     for(std::vector<simple_wml::document*>::iterator i = history_.begin();
01158         i != history_.end(); ++i) {
01159         buf += (*i)->output();
01160         delete *i;
01161     }
01162 
01163     simple_wml::document* doc = new simple_wml::document(buf.c_str(), simple_wml::INIT_STATIC);
01164     const simple_wml::string_span& data = doc->output_compressed();
01165     doc->compress();
01166     network::send_raw_data(data.begin(), data.size(), sock);
01167     history_.clear();
01168     history_.push_back(doc);
01169 }
01170 
01171 void game::record_data(simple_wml::document* data) {
01172     data->compress();
01173     history_.push_back(data);
01174 }
01175 
01176 void game::set_description(simple_wml::node* desc) {
01177     description_ = desc;
01178     if(!password_.empty()) {
01179         description_->set_attr("password", "yes");
01180     }
01181 }
01182 
01183 void game::set_termination_reason(const std::string& reason) {
01184     if (reason == "out of sync") {
01185         simple_wml::string_span era;
01186         if (level_.child("era")) {
01187             era = level_.child("era")->attr("id");
01188         }
01189         termination_ = "out of sync - " + era.to_string();
01190     }
01191     if (termination_.empty()) { termination_ = reason; }
01192 }
01193 
01194 void game::add_players(const game& other_game, const bool observer) {
01195     user_vector users = other_game.all_game_users();
01196     if (observer){
01197         observers_.insert(observers_.end(), users.begin(), users.end());
01198     }
01199     else{
01200         players_.insert(players_.end(), users.begin(), users.end());
01201     }
01202 }
01203 
01204 const user_vector game::all_game_users() const {
01205     user_vector res;
01206 
01207     res.insert(res.end(), players_.begin(), players_.end());
01208     res.insert(res.end(), observers_.begin(), observers_.end());
01209 
01210     return res;
01211 }
01212 
01213 std::string game::debug_player_info() const {
01214     std::stringstream result;
01215     result << "game id: " << id_ << "\n";
01216 //  result << "players_.size: " << players_.size() << "\n";
01217     for (user_vector::const_iterator p = players_.begin(); p != players_.end(); p++){
01218         const player_map::const_iterator user = player_info_->find(*p);
01219         if (user != player_info_->end()){
01220             result << "player: " << user->second.name().c_str() << "\n";
01221         }
01222         else{
01223             result << "player: '" << *p << "' not found\n";
01224         }
01225     }
01226 //  result << "observers_.size: " << observers_.size() << "\n";
01227     for (user_vector::const_iterator o = observers_.begin(); o != observers_.end(); o++){
01228         const player_map::const_iterator user = player_info_->find(*o);
01229         if (user != player_info_->end()){
01230             result << "observer: " << user->second.name().c_str() << "\n";
01231         }
01232         else{
01233             result << "observer: '" << *o << "' not found\n";
01234         }
01235     }
01236 /*  result << "player_info_: begin\n";
01237     for (player_map::const_iterator info = player_info_->begin(); info != player_info_->end(); info++){
01238         result << info->second.name().c_str() << "\n";
01239     }
01240     result << "player_info_: end\n";*/
01241     return result.str();
01242 }
01243 
01244 //! Find a user by name.
01245 player_map::const_iterator game::find_user(const simple_wml::string_span& name) const {
01246     player_map::const_iterator pl;
01247     for (pl = player_info_->begin(); pl != player_info_->end(); pl++) {
01248         if (name == pl->second.name().c_str()) {
01249             return pl;
01250         }
01251     }
01252     return player_info_->end();
01253 }
01254 
01255 void game::send_and_record_server_message(const char* message,
01256                                           const network::connection exclude)
01257 {
01258     simple_wml::document* doc = new simple_wml::document;
01259     send_server_message(message, 0, doc);
01260     send_data(*doc, exclude);
01261     if (started_) record_data(doc);
01262 }
01263 
01264 void game::send_server_message_to_all(const char* message, network::connection exclude) const
01265 {
01266     simple_wml::document doc;
01267     send_server_message(message, 0, &doc);
01268     send_data(doc, exclude);
01269 }
01270 
01271 void game::send_server_message(const char* message, network::connection sock, simple_wml::document* docptr) const
01272 {
01273     simple_wml::document docbuf;
01274     if(docptr == NULL) {
01275         docptr = &docbuf;
01276     }
01277 
01278     simple_wml::document& doc = *docptr;
01279     if (started_) {
01280         simple_wml::node& cmd = doc.root().add_child("turn");
01281         simple_wml::node& cfg = cmd.add_child("command");
01282         simple_wml::node& msg = cfg.add_child("speak");
01283         msg.set_attr("id", "server");
01284         msg.set_attr_dup("message", message);
01285     } else {
01286         simple_wml::node& msg = doc.root().add_child("message");
01287         msg.set_attr("sender", "server");
01288         msg.set_attr_dup("message", message);
01289     }
01290 
01291     if(sock) {
01292         send_to_one(doc, sock);
01293     }
01294 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs