00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "gui/dialogs/lobby/lobby_data.hpp"
00017
00018 #include "config.hpp"
00019 #include "game_preferences.hpp"
00020 #include "filesystem.hpp"
00021 #include "foreach.hpp"
00022 #include "formula_string_utils.hpp"
00023 #include "gettext.hpp"
00024 #include "network.hpp"
00025 #include "log.hpp"
00026 #include "map.hpp"
00027 #include "map_exception.hpp"
00028 #include "wml_exception.hpp"
00029
00030 #include <iterator>
00031
00032 static lg::log_domain log_config("config");
00033 #define ERR_CF LOG_STREAM(err, log_config)
00034 static lg::log_domain log_engine("engine");
00035 #define WRN_NG LOG_STREAM(warn, log_engine)
00036
00037 static lg::log_domain log_lobby("lobby");
00038 #define DBG_LB LOG_STREAM(info, log_lobby)
00039 #define LOG_LB LOG_STREAM(info, log_lobby)
00040 #define ERR_LB LOG_STREAM(err, log_lobby)
00041
00042 chat_message::chat_message(const time_t& timestamp, const std::string& user, const std::string& message)
00043 : timestamp(timestamp), user(user), message(message)
00044 {
00045 }
00046
00047 chat_log::chat_log()
00048 : history_()
00049 {
00050 }
00051
00052 void chat_log::add_message(const time_t& timestamp, const std::string& user, const std::string& message)
00053 {
00054 history_.push_back(chat_message(timestamp, user, message));
00055 }
00056
00057
00058 void chat_log::add_message(const std::string& user, const std::string& message) {
00059 add_message(time(NULL), user, message);
00060 }
00061
00062 void chat_log::clear()
00063 {
00064 history_.clear();
00065 }
00066
00067 room_info::room_info(const std::string& name)
00068 : name_(name)
00069 , members_()
00070 , log_()
00071 {
00072 }
00073
00074 bool room_info::is_member(const std::string& user) const
00075 {
00076 return members_.find(user) != members_.end();
00077 }
00078
00079 void room_info::add_member(const std::string& user)
00080 {
00081 members_.insert(user);
00082 }
00083
00084 void room_info::remove_member(const std::string& user)
00085 {
00086 members_.erase(user);
00087 }
00088
00089 void room_info::process_room_members(const config& data)
00090 {
00091 members_.clear();
00092 foreach (const config& m, data.child_range("member")) {
00093 members_.insert(m["name"]);
00094 }
00095 }
00096
00097 user_info::user_info(const config& c)
00098 : name(c["name"])
00099 , game_id(c["game_id"])
00100 , relation(ME)
00101 , state(game_id == 0 ? LOBBY : GAME)
00102 , registered(c["registered"].to_bool())
00103 , observing(c["status"] == "observing")
00104 {
00105 update_relation();
00106 }
00107
00108 void user_info::update_state(int selected_game_id, const room_info* current_room )
00109 {
00110 if (game_id != 0) {
00111 if (game_id == selected_game_id) {
00112 state = SEL_GAME;
00113 } else {
00114 state = GAME;
00115 }
00116 } else {
00117 if (current_room != NULL && current_room->is_member(name)) {
00118 state = SEL_ROOM;
00119 } else {
00120 state = LOBBY;
00121 }
00122 }
00123 update_relation();
00124 }
00125
00126 void user_info::update_relation()
00127 {
00128 if (name == preferences::login()) {
00129 relation = ME;
00130 } else if (preferences::is_ignored(name)) {
00131 relation = IGNORED;
00132 } else if (preferences::is_friend(name)) {
00133 relation = FRIEND;
00134 } else {
00135 relation = NEUTRAL;
00136 }
00137 }
00138
00139 namespace {
00140
00141 std::string make_short_name(const std::string& long_name)
00142 {
00143 if (long_name.empty()) return "";
00144 std::string sh;
00145 bool had_space = true;
00146 for (size_t i = 1; i < long_name.size(); ++i) {
00147 if (long_name[i] == ' ') {
00148 had_space = true;
00149 } else if (had_space && long_name[i] != '?') {
00150 sh += long_name[i];
00151 had_space = false;
00152 }
00153 }
00154 return sh;
00155 }
00156
00157 }
00158
00159 game_info::game_info(const config& game, const config& game_config)
00160 : mini_map()
00161 , id(game["id"])
00162 , map_data(game["map_data"])
00163 , name(game["name"])
00164 , scenario()
00165 , remote_scenario(false)
00166 , map_info()
00167 , map_size_info()
00168 , era()
00169 , era_short()
00170 , gold(game["mp_village_gold"])
00171 , support(game["mp_village_support"])
00172 , xp(game["experience_modifier"] + "%")
00173 , vision()
00174 , status()
00175 , time_limit()
00176 , vacant_slots(lexical_cast_default<int>(game["slots"], 0))
00177 , current_turn(0)
00178 , reloaded(game["savegame"].to_bool())
00179 , started(false)
00180 , fog(game["mp_fog"].to_bool())
00181 , shroud(game["mp_shroud"].to_bool())
00182 , observers(game["observer"].to_bool(true))
00183 , shuffle_sides(game["shuffle_sides"].to_bool(true))
00184 , use_map_settings(game["mp_use_map_settings"].to_bool())
00185 , verified(true)
00186 , password_required(game["password"].to_bool())
00187 , have_era(true)
00188 , has_friends(false)
00189 , has_ignored(false)
00190 , display_status(NEW)
00191 {
00192 std::string turn = game["turn"];
00193 if (!game["mp_era"].empty())
00194 {
00195 const config &era_cfg = game_config.find_child("era", "id", game["mp_era"]);
00196 utils::string_map symbols;
00197 symbols["era_id"] = game["mp_era"];
00198 if (era_cfg) {
00199 era = era_cfg["name"].str();
00200 era_short = era_cfg["short_name"].str();
00201 if (era_short.empty()) {
00202 era_short = make_short_name(era);
00203 }
00204 } else {
00205 have_era = !game["require_era"].to_bool(true);
00206 era = vgettext("Unknown era: $era_id", symbols);
00207 era_short = "?" + make_short_name(era);
00208 verified = false;
00209 }
00210 } else {
00211 era = _("Unknown era");
00212 era_short = "??";
00213 verified = false;
00214 }
00215 map_info = era;
00216
00217 if (map_data.empty()) {
00218 map_data = read_map(game["mp_scenario"]);
00219 }
00220
00221 if (map_data.empty()) {
00222 map_info += " — ??×??";
00223 } else {
00224 try {
00225 gamemap map(game_config, map_data);
00226
00227 std::ostringstream msi;
00228 msi << map.w() << utils::unicode_multiplication_sign << map.h();
00229 map_size_info = msi.str();
00230 map_info += " — " + map_size_info;
00231 } catch (incorrect_map_format_error &e) {
00232 ERR_CF << "illegal map: " << e.message << "\n";
00233 verified = false;
00234 } catch (twml_exception& e) {
00235 ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
00236 verified = false;
00237 }
00238 }
00239 map_info += " ";
00240 if (!game["mp_scenario"].empty())
00241 {
00242
00243 const config *level_cfg = &game_config.find_child("multiplayer", "id", game["mp_scenario"]);
00244 if (!*level_cfg) {
00245
00246 level_cfg = &game_config.find_child("generic_multiplayer", "id", game["mp_scenario"]);
00247 }
00248 if (*level_cfg) {
00249 scenario = (*level_cfg)["name"].str();
00250 map_info += scenario;
00251
00252
00253
00254 if (!reloaded) {
00255 if (const config& hashes = game_config.child("multiplayer_hashes")) {
00256 std::string hash = game["hash"];
00257 bool hash_found = false;
00258 foreach (const config::attribute &i, hashes.attribute_range()) {
00259 if (i.first == game["mp_scenario"] && i.second == hash) {
00260 hash_found = true;
00261 break;
00262 }
00263 }
00264 if(!hash_found) {
00265 remote_scenario = true;
00266 map_info += " — ";
00267 map_info += _("Remote scenario");
00268 verified = false;
00269 }
00270 }
00271 }
00272 } else {
00273 utils::string_map symbols;
00274 symbols["scenario_id"] = game["mp_scenario"];
00275 scenario = vgettext("Unknown scenario: $scenario_id", symbols);
00276 map_info += scenario;
00277 verified = false;
00278 }
00279 } else {
00280 scenario = _("Unknown scenario");
00281 map_info += scenario;
00282 verified = false;
00283 }
00284 if (reloaded) {
00285 map_info += " — ";
00286 map_info += _("Reloaded game");
00287 verified = false;
00288 }
00289
00290 if (!turn.empty()) {
00291 started = true;
00292 int index = turn.find_first_of('/');
00293 if (index > -1){
00294 const std::string current_turn_string = turn.substr(0, index);
00295 current_turn = lexical_cast<unsigned int>(current_turn_string);
00296 }
00297 status = _("Turn ") + turn;
00298 } else {
00299 started = false;
00300 if (vacant_slots > 0) {
00301 status = std::string(_n("Vacant Slot:", "Vacant Slots:",
00302 vacant_slots)) + " " + game["slots"];
00303 }
00304 }
00305
00306 if (fog) {
00307 vision = _("Fog");
00308 if (shroud) {
00309 vision += "/";
00310 vision += _("Shroud");
00311 }
00312 } else if (shroud) {
00313 vision = _("Shroud");
00314 } else {
00315 vision = _("none");
00316 }
00317 if (game["mp_countdown"].to_bool()) {
00318 time_limit = game["mp_countdown_init_time"].str() + "+"
00319 + game["mp_countdown_turn_bonus"].str() + "/"
00320 + game["mp_countdown_action_bonus"].str();
00321 } else {
00322 time_limit = "";
00323 }
00324 }
00325
00326 bool game_info::can_join() const
00327 {
00328 return have_era && !started && vacant_slots > 0;
00329 }
00330
00331 bool game_info::can_observe() const
00332 {
00333 return (have_era && observers) || preferences::is_authenticated();
00334 }
00335
00336 const char* game_info::display_status_string() const
00337 {
00338 switch (display_status) {
00339 case game_info::CLEAN:
00340 return "clean";
00341 case game_info::NEW:
00342 return "new";
00343 case game_info::DELETED:
00344 return "deleted";
00345 case game_info::UPDATED:
00346 return "updated";
00347 default:
00348 ERR_CF << "BAD display_status " << display_status
00349 << " in game " << id << "\n";
00350 return "?";
00351 }
00352 }
00353
00354 game_filter_stack::game_filter_stack()
00355 : filters_()
00356 {
00357 }
00358
00359 game_filter_stack::~game_filter_stack()
00360 {
00361 foreach (game_filter_base* f, filters_) {
00362 delete f;
00363 }
00364 }
00365
00366 void game_filter_stack::append(game_filter_base *f)
00367 {
00368 filters_.push_back(f);
00369 }
00370
00371 void game_filter_stack::clear()
00372 {
00373 foreach (game_filter_base* f, filters_) {
00374 delete f;
00375 }
00376 filters_.clear();
00377 }
00378
00379 bool game_filter_and_stack::match(const game_info &game) const
00380 {
00381 foreach (game_filter_base* f, filters_) {
00382 if (!f->match(game)) return false;
00383 }
00384 return true;
00385 }
00386
00387 bool game_filter_general_string_part::match(const game_info &game) const
00388 {
00389 const std::string& s1 = game.map_info;
00390 const std::string& s2 = game.name;
00391 return
00392 std::search(
00393 s1.begin(), s1.end(), value_.begin(), value_.end(), chars_equal_insensitive
00394 ) != s1.end()
00395 ||
00396 std::search(
00397 s2.begin(), s2.end(), value_.begin(), value_.end(), chars_equal_insensitive
00398 ) != s2.end();
00399 }
00400