diff --git a/data/core/images/lobby/status-idle-f.png b/data/core/images/lobby/status-idle-f.png new file mode 100644 index 00000000000..20421c4cb62 Binary files /dev/null and b/data/core/images/lobby/status-idle-f.png differ diff --git a/data/core/images/lobby/status-idle-i.png b/data/core/images/lobby/status-idle-i.png new file mode 100644 index 00000000000..669ef93fc69 Binary files /dev/null and b/data/core/images/lobby/status-idle-i.png differ diff --git a/data/core/images/lobby/status-idle-n.png b/data/core/images/lobby/status-idle-n.png new file mode 100644 index 00000000000..91a71e31418 Binary files /dev/null and b/data/core/images/lobby/status-idle-n.png differ diff --git a/data/core/images/lobby/status-idle-s.png b/data/core/images/lobby/status-idle-s.png new file mode 100644 index 00000000000..50b9e18ad4d Binary files /dev/null and b/data/core/images/lobby/status-idle-s.png differ diff --git a/data/core/images/lobby/status-lobby-f.png b/data/core/images/lobby/status-lobby-f.png new file mode 100644 index 00000000000..5b3d590f9c3 Binary files /dev/null and b/data/core/images/lobby/status-lobby-f.png differ diff --git a/data/core/images/lobby/status-lobby-i.png b/data/core/images/lobby/status-lobby-i.png new file mode 100644 index 00000000000..b5e0dbb5d59 Binary files /dev/null and b/data/core/images/lobby/status-lobby-i.png differ diff --git a/data/core/images/lobby/status-lobby-n.png b/data/core/images/lobby/status-lobby-n.png new file mode 100644 index 00000000000..90c4d960d56 Binary files /dev/null and b/data/core/images/lobby/status-lobby-n.png differ diff --git a/data/core/images/lobby/status-lobby-s.png b/data/core/images/lobby/status-lobby-s.png new file mode 100644 index 00000000000..97b882f2442 Binary files /dev/null and b/data/core/images/lobby/status-lobby-s.png differ diff --git a/data/core/images/lobby/status-obs-f.png b/data/core/images/lobby/status-obs-f.png new file mode 100644 index 00000000000..3d48830d371 Binary files /dev/null and b/data/core/images/lobby/status-obs-f.png differ diff --git a/data/core/images/lobby/status-obs-i.png b/data/core/images/lobby/status-obs-i.png new file mode 100644 index 00000000000..727fb0bf2b9 Binary files /dev/null and b/data/core/images/lobby/status-obs-i.png differ diff --git a/data/core/images/lobby/status-obs-n.png b/data/core/images/lobby/status-obs-n.png new file mode 100644 index 00000000000..5ea0248e396 Binary files /dev/null and b/data/core/images/lobby/status-obs-n.png differ diff --git a/data/core/images/lobby/status-playing-f.png b/data/core/images/lobby/status-playing-f.png new file mode 100644 index 00000000000..4ca90d955e1 Binary files /dev/null and b/data/core/images/lobby/status-playing-f.png differ diff --git a/data/core/images/lobby/status-playing-i.png b/data/core/images/lobby/status-playing-i.png new file mode 100644 index 00000000000..1357f3f24cb Binary files /dev/null and b/data/core/images/lobby/status-playing-i.png differ diff --git a/data/core/images/lobby/status-playing-n.png b/data/core/images/lobby/status-playing-n.png new file mode 100644 index 00000000000..18b42a66169 Binary files /dev/null and b/data/core/images/lobby/status-playing-n.png differ diff --git a/data/gui/default/window/lobby_main.cfg b/data/gui/default/window/lobby_main.cfg index 8daa22b92c3..018715938a0 100644 --- a/data/gui/default/window/lobby_main.cfg +++ b/data/gui/default/window/lobby_main.cfg @@ -203,11 +203,20 @@ definition = "default" [grid] [row] + [column] + border = "all" + border_size = 1 + [image] + id = "main_icon" + definition = "default" + label = "" + [/image] + [/column] [column] grow_factor = 1 horizontal_grow = "true" - border = "all" - border_size = 5 + border = "top,right,bottom" + border_size = 3 [label] id = "player" definition = "default" diff --git a/src/gui/dialogs/lobby_main.cpp b/src/gui/dialogs/lobby_main.cpp index 4557f8d122d..2b89a638f29 100644 --- a/src/gui/dialogs/lobby_main.cpp +++ b/src/gui/dialogs/lobby_main.cpp @@ -194,7 +194,7 @@ tlobby_main::tlobby_main(const config& game_config, lobby_info& info) , gamelistbox_(NULL), chat_log_container_(NULL) , chat_input_(NULL), window_(NULL) , lobby_info_(info), preferences_callback_(NULL) -, open_windows_(), active_window_(0) +, open_windows_(), active_window_(0), selected_game_id_() { } @@ -230,6 +230,11 @@ void set_visible_if_exists(tgrid* grid, const char* id, bool visible) } } +std::string colorize(const std::string& str, const std::string& color) +{ + return "" + str + ""; +} + } //end anonymous namespace void tlobby_main::update_gamelist() @@ -309,11 +314,50 @@ void tlobby_main::update_gamelist() } } update_selected_game(); + + lobby_info_.update_user_statuses(selected_game_id_, active_window_room()); userlistbox_->clear(); foreach (const user_info& user, lobby_info_.users()) { std::map data; - add_label_data(data, "player", user.name); + std::stringstream icon_ss; + std::string name = user.name; + icon_ss << "lobby/status"; + switch (user.state) { + case user_info::SEL_ROOM: + /* fall through */ + case user_info::LOBBY: + icon_ss << "-lobby"; + break; + case user_info::SEL_GAME: + name = colorize(name, "cyan"); + icon_ss << (user.observing ? "-obs" : "-playing"); + break; + case user_info::GAME: + name = colorize(name, "red"); + icon_ss << (user.observing ? "-obs" : "-playing"); break; + default: + ERR_NG << "Bad user state in lobby: " << user.state << "\n"; + } + switch (user.relation) { + case user_info::ME: + /* fall through */ + case user_info::NEUTRAL: + icon_ss << "-n"; + break; + case user_info::FRIEND: + icon_ss << "-f"; + break; + case user_info::IGNORED: + icon_ss << "-i"; + break; + default: + ERR_NG << "Bad user relation in lobby: " << user.relation << "\n"; + } + icon_ss << ".png"; + add_label_data(data, "player", name); + add_label_data(data, "main_icon", icon_ss.str()); + userlistbox_->add_row(data); } window_->invalidate_layout(); @@ -327,6 +371,9 @@ void tlobby_main::update_selected_game() const game_info& game = *lobby_info_.games_filtered()[idx]; can_observe = game.can_observe(); can_join = game.can_join(); + selected_game_id_ = game.id; + } else { + selected_game_id_ = 0; } window_->get_widget("observe_global", false).set_active(can_observe); window_->get_widget("join_global", false).set_active(can_join); @@ -392,6 +439,12 @@ void tlobby_main::post_show(twindow& /*window*/) window_ = NULL; } +room_info* tlobby_main::active_window_room() +{ + const tlobby_chat_window& t = open_windows_[active_window_]; + if (t.whisper) return NULL; + return lobby_info_.get_room(t.name); +} tlobby_chat_window* tlobby_main::room_window_open(const std::string& room, bool open_new) { @@ -735,7 +788,7 @@ bool tlobby_main::do_game_join(int idx, bool observe) } config response; config& join = response.add_child("join"); - join["id"] = game.id; + join["id"] = lexical_cast(game.id); join["observe"] = observe ? "yes" : "no"; if (join && game.password_required) { std::string password; diff --git a/src/gui/dialogs/lobby_main.hpp b/src/gui/dialogs/lobby_main.hpp index 3dc07e3cc7c..b21f7c7b345 100644 --- a/src/gui/dialogs/lobby_main.hpp +++ b/src/gui/dialogs/lobby_main.hpp @@ -115,6 +115,12 @@ private: */ legacy_result legacy_result_; + /** + * Get the room* corresponding to the currently active window, or NULL + * if a whisper window is active at the moment + */ + room_info* active_window_room(); + /** * Check if a room window for "room" is open, if open_new is true * then it will be created if not found. @@ -300,6 +306,8 @@ private: ttoggle_button* filter_invert_; ttext_box* filter_text_; + + int selected_game_id_; }; } // namespace gui2 diff --git a/src/lobby_data.cpp b/src/lobby_data.cpp index 758c3bd8757..7d3ce8e0398 100644 --- a/src/lobby_data.cpp +++ b/src/lobby_data.cpp @@ -96,15 +96,17 @@ user_info::user_info() , relation(ME) , state(LOBBY) , registered() + , observing() { } user_info::user_info(const config& c) : name(c["name"]) - , game_id(c["game_id"]) + , game_id(lexical_cast_default(c["game_id"])) , relation(ME) - , state(c["available"] == "no" ? GAME : LOBBY) + , state(game_id == 0 ? LOBBY : GAME) , registered(utils::string_bool(c["registered"])) + , observing(c["status"] == "observing") { if (name == preferences::login()) { relation = ME; @@ -117,12 +119,20 @@ user_info::user_info(const config& c) } } -void user_info::update_state(const std::string& selected_game_id, const room_info* current_room /*= NULL*/) +void user_info::update_state(int selected_game_id, const room_info* current_room /*= NULL*/) { - if (!game_id.empty() && game_id == selected_game_id) { - state = SEL_GAME; - } else if (state == LOBBY && current_room != NULL && current_room->is_member(name)) { - state = SEL_ROOM; + if (game_id != 0) { + if (game_id == selected_game_id) { + state = SEL_GAME; + } else { + state = GAME; + } + } else if (state == LOBBY) { + if (current_room != NULL && current_room->is_member(name)) { + state = SEL_ROOM; + } else { + state = LOBBY; + } } } @@ -178,7 +188,7 @@ std::string make_short_name(const std::string long_name) game_info::game_info(const config& game, const config& game_config) : mini_map() -, id(game["id"]) +, id(lexical_cast_default(game["id"])) , map_data(game["map_data"]) , name(game["name"]) , scenario() @@ -456,8 +466,8 @@ void lobby_info::parse_gamelist() games_by_id_.insert(std::make_pair(gi.id, &gi)); } foreach (user_info& ui, users_) { - if (!ui.game_id.empty()) { - std::map::iterator i = games_by_id_.find(ui.game_id); + if (ui.game_id != 0) { + std::map::iterator i = games_by_id_.find(ui.game_id); if (i == games_by_id_.end()) { WRN_NG << "User " << ui.name << " has unknown game_id: " << ui.game_id << "\n"; } else { @@ -551,3 +561,10 @@ void lobby_info::apply_game_filter() } } } + +void lobby_info::update_user_statuses(int game_id, const room_info *room) +{ + foreach (user_info& user, users_) { + user.update_state(game_id, room); + } +} diff --git a/src/lobby_data.hpp b/src/lobby_data.hpp index 1ba2333dab4..15805cc6592 100644 --- a/src/lobby_data.hpp +++ b/src/lobby_data.hpp @@ -88,7 +88,7 @@ struct user_info user_info(); user_info(const config& c); - void update_state(const std::string& selected_game_id, const room_info* current_room = NULL); + void update_state(int selected_game_id, const room_info* current_room = NULL); enum user_relation { ME, FRIEND, NEUTRAL, IGNORED }; enum user_state { LOBBY, SEL_ROOM, GAME, SEL_GAME }; @@ -96,10 +96,11 @@ struct user_info bool operator> (const user_info& b) const; std::string name; - std::string game_id; + int game_id; user_relation relation; user_state state; bool registered; + bool observing; }; /** @@ -114,7 +115,7 @@ struct game_info bool can_observe() const; surface mini_map; - std::string id; + int id; std::string map_data; std::string name; std::string scenario; @@ -269,6 +270,8 @@ public: chat_log& get_whisper_log(const std::string& name); + void update_user_statuses(int game_id, const room_info* room); + const std::vector& rooms() const { return rooms_; } const std::vector& games() const { return games_; } const std::vector& games_filtered(); @@ -281,7 +284,7 @@ private: bool gamelist_initialized_; std::vector rooms_; std::vector games_; - std::map games_by_id_; + std::map games_by_id_; std::vector games_filtered_; std::vector users_; std::map whispers_; diff --git a/src/server/game.cpp b/src/server/game.cpp index 482505304dd..bfd980113ee 100644 --- a/src/server/game.cpp +++ b/src/server/game.cpp @@ -74,7 +74,7 @@ game::game(player_map& players, const network::connection host, } // Mark the host as unavailable in the lobby. pl->second.mark_available(id_, name_); - p1->second.set_status(player::PLAYING); + pl->second.set_status(player::PLAYING); } game::~game() @@ -277,7 +277,7 @@ void game::update_side_data() { // * Find the username. // * Find the side this username corresponds to. for (user_vector::const_iterator user = users.begin(); user != users.end(); ++user) { - const player_map::const_iterator info = player_info_->find(*user); + player_map::iterator info = player_info_->find(*user); if (info == player_info_->end()) { ERR_GAME << "Game: " << id_ << " ERROR: unable to find user info for connection: " @@ -343,7 +343,7 @@ void game::transfer_side_control(const network::connection sock, const simple_wm const simple_wml::string_span& newplayer_name = cfg["player"]; const network::connection old_player = sides_[side_num - 1]; - const player_map::const_iterator oldplayer = player_info_->find(old_player); + const player_map::iterator oldplayer = player_info_->find(old_player); if (oldplayer == player_info_->end()) { WRN_GAME << "Could not find old player in player_info_. (socket: " << old_player << ")\n"; @@ -380,7 +380,7 @@ void game::transfer_side_control(const network::connection sock, const simple_wm return; } //find the player that is passed control - player_map::const_iterator newplayer; + player_map::iterator newplayer; for (newplayer = player_info_->begin(); newplayer != player_info_->end(); newplayer++) { if (newplayer_name == newplayer->second.name().c_str()) { break; @@ -1044,7 +1044,7 @@ bool game::remove_player(const network::connection player, const bool disconnect if (*side != player) continue; if (side_controllers_[side_num] == "ai") ai_transfer = true; - player_map::const_iterator o = player_info_->find(owner_); + player_map::iterator o = player_info_->find(owner_); const std::string owner_name = (o != player_info_->end() ? o->second.name() : "(unknown)"); change_controller(side_num, owner_, owner_name); // Check whether the host is actually a player and make him one if not.