47 #include <boost/algorithm/string/predicate.hpp>
49 #include <boost/make_shared.hpp>
52 #define ERR_CF LOG_STREAM(err, log_config)
55 #define ERR_MP LOG_STREAM(err, log_lobby)
56 #define WRN_MP LOG_STREAM(warn, log_lobby)
57 #define LOG_MP LOG_STREAM(info, log_lobby)
58 #define DBG_MP LOG_STREAM(debug, log_lobby)
67 gold_icon_locator_(
"themes/gold.png"),
68 xp_icon_locator_(
"themes/units.png"),
69 map_size_icon_locator_(
"misc/map.png"),
70 vision_icon_locator_(
"misc/visibility.png"),
71 time_limit_icon_locator_(
"themes/sand-clock.png"),
72 observer_icon_locator_(
"misc/eye.png"),
73 no_observer_icon_locator_(
"misc/no_observer.png"),
74 shuffle_sides_icon_locator_(
"misc/shuffle-sides.png"),
75 map_hashes_(map_hashes),
78 minimap_size_(item_height_ - 2*margin_),
80 h_padding_image_to_text_(4),
83 visible_range_(
std::pair<size_t,size_t>(0,0)),
87 double_clicked_(false),
88 ignore_next_doubleclick_(false),
89 last_was_doubleclick_(false)
113 const SDL_Rect
res = { 0, 0, 0, 0 };
153 int xpos = item_rect.x +
margin_;
154 int ypos = item_rect.y +
margin_;
165 SDL_Color font_color;
184 no_era_string =
_(
" (Unknown Era)");
192 no_era_string +=
_(
" (Need to download addons)");
194 no_era_string +=
_(
" (Outdated addons)");
202 const int status_text_width = status_text ? status_text->w : 0;
207 (item_rect.x + item_rect.w) - xpos - margin_ - status_text_width -
h_padding_),
215 ypos + name_surf->h - status_text->h, status_text);
219 ypos = item_rect.y + item_rect.h/3 +
margin_;
224 (item_rect.x + item_rect.w) - xpos - margin_),
231 ypos = item_rect.y + 2*item_rect.h/3 -
margin_;
236 (item_rect.x + item_rect.w) - xpos - margin_),
238 if(era_and_mod_info_surf) {
239 video().
blit_surface(xpos, ypos - era_and_mod_info_surf->h/2, era_and_mod_info_surf);
243 ypos = item_rect.y + item_rect.h -
margin_;
253 ypos -= observer_icon->h/2;
346 (item_rect.x + item_rect.w) - xpos - margin_),
358 (item_rect.x + item_rect.w) - xpos - margin_),
368 scrollarea::handle_event(event);
369 if(event.type == SDL_KEYDOWN) {
371 switch(event.key.keysym.sym) {
389 selected_ =
static_cast<size_t>(std::max<long>(
static_cast<long>(
selected_) - items_on_screen, 0));
416 }
else if((event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT) || event.type ==
DOUBLE_CLICK_EVENT) {
419 if(event.type == SDL_MOUSEBUTTONDOWN) {
423 x =
reinterpret_cast<size_t>(
event.user.data1);
424 y =
reinterpret_cast<size_t>(
event.user.data2);
451 SDL_PeepEvents(&ev, 1, SDL_PEEKEVENT,
467 if (game[
"mp_campaign"].
empty()) {
468 if (!game[
"mp_scenario"].
empty()) {
471 "id", game[
"mp_scenario"]);
474 level_cfg = &game_config.
find_child(
"generic_multiplayer",
475 "id", game[
"mp_scenario"]);
480 item.
map_info += (*level_cfg)[
"name"].str();
486 bool hash_found =
false;
489 if (
i.first == game[
"mp_scenario"] &&
503 if ((*level_cfg)[
"require_scenario"].to_bool(
false)) {
510 symbols[
"scenario_id"] = game[
"mp_scenario"];
512 vgettext(
"Unknown scenario: $scenario_id", symbols);
515 if (game[
"require_scenario"].to_bool(
false)) {
523 if (game[
"require_scenario"].to_bool(
false)) {
529 game[
"mp_campaign"]);
533 item.
map_info += (*level_cfg)[
"name"].str();
535 item.
map_info += game[
"mp_scenario_name"].str();
538 const std::vector<std::string> difficulties =
541 (*level_cfg)[
"difficulty_descriptions"];
542 std::vector<std::string> difficulty_options =
547 assert(difficulties.size() == difficulty_options.size());
548 for (
const std::string& difficulty : difficulties) {
549 if (difficulty == game[
"difficulty_define"]) {
563 symbols[
"campaign_id"] = game[
"mp_campaign"];
565 vgettext(
"Unknown campaign: $campaign_id", symbols);
568 if (game[
"require_scenario"].to_bool(
false)) {
593 std::vector<minimap_cache_item> minimap_cache;
599 minimap_cache.push_back(item);
602 item.
map_data = game[
"map_data"].str();
610 for(i = minimap_cache.begin(); i != minimap_cache.end() && !found; ++
i) {
619 gamemap map(boost::make_shared<terrain_type_data>(game_config), item.
map_data);
622 + std::to_string(map.
h());
641 if (
const config & game_req = game.
find_child(
"addon",
"id", local_item[
"addon_id"])) {
644 r.
addon_id = local_item[
"addon_id"].str();
646 const version_info local_ver(local_item[
"addon_version"].str());
647 version_info local_min_ver(local_item.
has_attribute(
"addon_min_version") ? local_item[
"addon_min_version"] : local_item[
"addon_version"]);
649 if (local_min_ver > local_ver) {
651 local_min_ver = local_ver;
654 const version_info remote_ver(game_req[
"version"].str());
655 version_info remote_min_ver(game_req.has_attribute(
"min_version") ? game_req[
"min_version"] : game_req[
"version"]);
656 if (remote_min_ver > remote_ver) {
657 remote_min_ver = remote_ver;
661 if (local_min_ver > remote_ver) {
666 symbols[
"host_ver"] = remote_ver.
str();
667 symbols[
"local_ver"] = local_ver.
str();
668 r.
message =
vgettext(
"Host's version of $addon is too old: host's version $host_ver < your version $local_ver.", symbols);
669 req_list.push_back(r);
674 if (remote_min_ver > local_ver) {
679 symbols[
"host_ver"] = remote_ver.
str();
680 symbols[
"local_ver"] = local_ver.
str();
681 r.
message =
vgettext(
"Your version of $addon is out of date: host's version $host_ver > your version $local_ver.", symbols);
682 req_list.push_back(r);
693 if (!game[
"mp_era"].
empty())
695 const config &era_cfg = game_config.
find_child(
"era",
"id", game[
"mp_era"]);
697 symbols[
"era_id"] = game[
"mp_era"];
706 if (!game[
"require_era"].to_bool(
true)) {
739 if (
m[
"require_modification"].to_bool(
false)) {
756 if (addon.has_attribute(
"id")) {
757 if (
std::find(installed_addons.begin(), installed_addons.end(), addon[
"id"].str()) == installed_addons.end()) {
763 symbols[
"id"] = addon[
"id"].str();
777 bool verified =
true;
779 item.
reloaded = game[
"savegame"].to_bool();
794 item.
id = game[
"id"].str();
795 item.
name = game[
"name"].str();
798 item.
vacant_slots = lexical_cast_default<size_t>(slots, 0);
802 int index = turn.find_first_of(
'/');
804 const std::string current_turn = turn.substr(0, index);
807 item.
status =
_(
"Turn ") + turn;
820 item.
gold = game[
"mp_village_gold"].str();
821 if (game[
"mp_fog"].to_bool()) {
824 if (game[
"mp_shroud"].to_bool()) {
831 }
else if (game[
"mp_shroud"].to_bool()) {
840 if (game[
"mp_countdown"].to_bool()) {
841 item.
time_limit = game[
"mp_countdown_init_time"].str() +
" / +"
842 + game[
"mp_countdown_turn_bonus"].str() +
" "
843 + game[
"mp_countdown_action_bonus"].str();
847 item.
xp = game[
"experience_modifier"].str() +
"%";
849 item.
observers = game[
"observer"].to_bool(
true);
884 if (!selected_game.empty()) {
885 for (
unsigned int i=0;
i <
games_.size();
i++) {
886 if (
games_[
i].
id == selected_game) {
895 if (scrolled_to_max) {
909 if (
id.
empty())
return;
911 for (
unsigned int i=0;
i <
games_.size();
i++) {
927 bool found_friend =
false;
940 bool found_match =
true;
972 return basic_sorter::column_sortable(column);
984 if(row1.
id >= nb || row2.
id >= nb) {
989 std::advance(gi, row1.
id);
990 const config &game1 = *gi;
992 std::advance(gi, row2.
id);
993 const config &game2 = *gi;
995 if(column == MAP_COLUMN) {
996 size_t mapsize1 = game1[
"map_data"].str().size();
998 mapsize1 = game1[
"map"].str().size();
1001 size_t mapsize2 = game2[
"map_data"].str().size();
1003 mapsize2 = game2[
"map"].str().size();
1006 return mapsize1 < mapsize2;
1008 }
else if(column == STATUS_COLUMN) {
1009 int nslots1 = game1[
"slots"].to_int();
1010 int nslots2 = game2[
"slots"].to_int();
1012 int turn1 = game1[
"turn"].to_int();
1013 int turn2 = game2[
"turn"].to_int();
1015 if(nslots1 > nslots2) {
1017 }
else if(nslots1 < nslots2) {
1020 return turn1 < turn2;
1024 return basic_sorter::less(column,row1,row2);
1028 mp::
ui(v, wesnothd_connection,
_(
"Game Lobby"), cfg, c, gamelist),
1052 std::vector<std::string> replay_options_strings_;
1053 replay_options_strings_.push_back(
_(
"Normal Replays"));
1054 replay_options_strings_.push_back(
_(
"Quick Replays"));
1055 replay_options_strings_.push_back(
_(
"Enter Blindfolded"));
1059 std::string help_string1 =
_(
"Skip quickly to the active turn when observing");
1060 std::string help_string2 =
_(
"Do not show the map until given control of a side");
1148 if (space < btn_space) space = btn_space;
1195 std::string e_title =
_(
"Incompatible user-made content.");
1196 std::string err_msg =
_(
"This game cannot be joined because the host has out-of-date add-ons which are incompatible with your version. You might suggest to them that they update their add-ons.");
1199 err_msg +=
_(
"Details:");
1204 err_msg +=
a.message;
1211 std::string err_msg =
_(
"This game requires one or more user-made addons to be installed or updated in order to join. Do you want to try to install them?");
1214 err_msg +=
_(
"Details:");
1217 std::vector<std::string> needs_download;
1220 err_msg +=
a.message;
1223 needs_download.push_back(
a.addon_id);
1228 assert(needs_download.size() > 0);
1249 gui2::show_error_message(
video(),
_(
"Something is wrong with the addon version check database supporting the multiplayer lobby, please report this at bugs.wesnoth.org."));
1280 if(join || observe) {
1294 join[
"id"] = game.
id;
1295 join[
"observe"] = observe;
1297 if(!password.empty()) {
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
child_itors child_range(const std::string &key)
static lg::log_domain log_config("config")
surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::map< map_location, unsigned int > *reach_map)
function to create the minimap for a given map the surface returned must be freed by the user ...
void populate_game_item_campaign_or_scenario_info(game_item &, const config &, const config &, bool &)
image::locator time_limit_icon_locator_
void show_error_message(CVideo &video, const std::string &message, bool message_use_markup)
Shows an error message to the user.
void set_filter_lobby(bool value)
bool selected_user_changed() const
virtual void process_event()
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
image::locator shuffle_sides_icon_locator_
unsigned int row_height() const
static lg::log_domain log_lobby("mp/lobby")
bool plugin_event_helper(const process_event_data &)
std::string search_string_
std::vector< bool > game_observers_
void set_inner_location(const SDL_Rect &rect)
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
boost::scoped_ptr< plugins_context > plugins_context_
void populate_game_item(game_item &, const config &, const config &, const std::vector< std::string > &)
std::vector< game_item > games_
void set_fi_vacant_slots(bool value)
gui::button friends_in_game_
std::vector< bool > game_vacant_slots_
virtual void layout_children(const SDL_Rect &rect)
Lays the children out.
result get_result()
Returns the result of the current widget.
attribute_map::value_type attribute
bool ignore_next_doubleclick_
std::vector< std::string > empty_string_vector
void set_text(const std::string &text, const SDL_Color &color=font::NORMAL_COLOR)
void draw_row(const size_t row_index, const SDL_Rect &rect, ROW_TYPE type)
gui::button observe_game_
GLint GLint GLint GLint GLint GLint y
const std::string unicode_multiplication_sign
void set_fi_friends_in_game(bool value)
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
const std::string text() const
const config & child_or_empty(const std::string &key) const
Returns the first child with the given key, or an empty config if there is none.
const std::vector< required_addon > * selection_addon_requirements() const
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
To lexical_cast(From value)
Lexical cast converts one type to another.
void set_fi_text(const std::string &search_string)
const SDL_Color NORMAL_COLOR
void process_event_impl(const process_event_data &)
game_item selected_game()
const SDL_Color GOOD_COLOR
lobby_sorter(const config &cfg)
virtual void process_network_data(const config &data)
Processes any pending network data.
virtual void hide_children(bool hide=true)
Hides or shows all gui::widget children of this widget.
std::vector< required_addon > addons
bool contains(const tpane::titem &item, const std::string &tag, const ttext_box &text_box)
A filter testing whether a search string is used in a text.
This module controls the multiplayer lobby.
STRIP_SPACES : strips leading and trailing blank spaces.
bool selection_is_joinable() const
const SDL_Color DISABLED_COLOR
void set_game_items(const config &cfg, const config &game_config, const std::vector< std::string > &installed_addons)
unsigned int current_turn
static UNUSEDNOWARN std::string _(const char *str)
bool chars_equal_insensitive(char a, char b)
Dialog is closed with ok button.
std::map< std::string, t_string > string_map
bool is_friend(const std::string &nick)
A class that represents a TCP/IP connection to the wesnothd server.
image::locator xp_icon_locator_
result set_result(result res)
Sets the result of this dialog, to be checked by get_result().
bool ad_hoc_addon_fetch_session(CVideo &v, const std::vector< std::string > &addon_ids)
Conducts an ad-hoc add-ons server connection to download an add-on with a particular id and all it's ...
bool last_was_doubleclick_
const SDL_Color BAD_COLOR
static const int xscale_base
const std::vector< std::string > & installed_addons_
void set_selected_user_changed(const bool &changed)
const config & game_config() const
Returns the main game config, as defined by loading the preprocessed WML files.
std::string era_and_mod_info
GLubyte GLubyte GLubyte GLubyte w
virtual void hide_children(bool hide=true)
Hides or shows all gui::widget children of this widget.
int w() const
Effective map width.
void show_message(CVideo &video, const std::string &title, const std::string &message, const std::string &button_caption, const bool auto_close, const bool message_use_markup)
Shows a message to the user.
GLboolean GLboolean GLboolean GLboolean a
std::string dev_message
The message for developers telling which problem was triggered, this shouldn't be translated...
const gui::label & title() const
Encapsulates the map of the game.
static UNUSEDNOWARN std::string _n(const char *str1, const char *str2, int n)
void set_fi_invert(bool value)
bool selection_is_observable() const
config & add_child(const std::string &key)
std::vector< std::string > installed_addons()
Retrieves the names of all installed add-ons.
void send_to_server(const config &cfg) override
Modify, read and display user preferences.
unsigned int item_height_
void handle_event(const SDL_Event &event)
void scroll(unsigned int pos)
image::locator vision_icon_locator_
void set_blindfold_replay(bool value)
void set_message_private(bool value)
gui::button apply_filter_
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
std::string read_map(const std::string &name)
std::string str() const
Serializes the version number into string form.
bool less(int column, const gui::menu::item &row1, const gui::menu::item &row2) const
GLenum GLenum GLvoid GLvoid * column
SDL_Rect draw_text(surface &dst, const SDL_Rect &area, int size, const SDL_Color &color, const std::string &txt, int x, int y, bool use_tooltips, int style)
Function to draw text on a surface.
A class which implements an approximation of template typedef scoped_resource scoped_ptr;.
std::map< std::string, std::string > minimaps_
gui::button game_preferences_
void send_chat_message(const std::string &message, bool allies_only=false)
#define DOUBLE_CLICK_EVENT
gui::combo replay_options_
lobby(CVideo &v, twesnothd_connection *wesnothd_connection, const config &cfg, chat &c, config &gamelist, const std::vector< std::string > &installed_addons)
static void handle_addon_requirements_gui(CVideo &v, const std::vector< required_addon > &reqs, mp::ADDON_REQ addon_outcome)
image::locator map_size_icon_locator_
SDL_Rect client_area() const
int h() const
Effective map height.
void set_selected(int val)
std::pair< size_t, size_t > visible_range_
const std::string space
whitespace is possible
std::string map_info_size
Game configuration data as global variables.
const_attr_itors attribute_range() const
static bool execute(std::string &password, CVideo &video)
The execute function – see tdialog for more information.
void assign(const resource_type &o)
ADDON_REQ selection_addon_outcome() const
config & gamelist()
Returns the current gamelist.
bool selection_needs_addons() const
GLfloat GLfloat GLfloat GLfloat h
GLint GLint GLint GLint GLint x
void set_items(const std::vector< std::string > &items)
Declarations for File-IO.
std::string map_info_size
void set_skip_mp_replay(bool value)
GLdouble GLdouble GLdouble r
gui::button vacant_slots_
void populate_game_item_era_info(game_item &, const config &, const config &, bool &)
unsigned child_count(const std::string &key) const
Represents version numbers.
void populate_game_item_map_info(game_item &, const config &, const config &, bool &)
std::string make_text_ellipsis(const std::string &text, int font_size, int max_width, int style)
If the text exceeds the specified max width, end it with an ellipsis (...)
static mp::ADDON_REQ check_addon_version_compatibility(const config &local_item, const config &game, std::vector< required_addon > &req_list)
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
bool fi_friends_in_game()
#define SDL_EVENTMASK(EVENT)
gui::button invert_filter_
gamebrowser(CVideo &video, const config &map_hashes)
Contains the SDL_Rect helper code.
image::locator observer_icon_locator_
SDL_Rect get_item_rect(size_t index) const
bool has_attribute(const std::string &key) const
int h_padding_image_to_text_
image::locator gold_icon_locator_
bool find(E event, F functor)
Tests whether an event handler is available.
void set_selected_game(const std::string &game_name)
Sets the name of the selected game which is used to highlight the names of the players which have joi...
bool column_sortable(int column) const
virtual void process_network_data(const config &data)
Processes any pending network data.
void play_music_repeatedly(const std::string &id)
image::locator no_observer_icon_locator_
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
const SDL_Color GRAY_COLOR
config & find_child(const std::string &key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Standard logging facilities (interface).
bool game_matches_filter(const game_item &i, const config &cfg)
const std::function< std::string(const config &, const std::string &) > get_str
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
this class memorizes a chat session.
const SDL_Color YELLOW_COLOR
void select_game(const std::string &id)
void populate_game_item_addons_installed(game_item &, const config &, const std::vector< std::string > &)
std::string get_selected_user_game()
A config object defines a single node in a WML file, with access to child nodes.
surface get_rendered_text(const std::string &str, int size, const SDL_Color &color, int style)
Helper class, don't construct this directly.
bool registered_users_only
void update_rect(const SDL_Rect &)
Interfaces for manipulating version numbers of engine, add-ons, etc.
virtual void gamelist_updated(bool silent=true)
Called each time the gamelist_ variable is updated.
GLsizei const GLcharARB ** string
const config & map_hashes_
Shows a yes and no button.
virtual void layout_children(const SDL_Rect &rect)
Lays the children out.
a base class for the different multiplayer base dialogs: game list, create game, wait game...
virtual void gamelist_updated(bool silent=true)
Called each time the gamelist_ variable is updated.
void populate_game_item_mod_info(game_item &, const config &, const config &, bool &)
gui::textbox filter_text_