The Battle for Wesnoth  1.15.1+dev
mp_staging.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by the Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #define GETTEXT_DOMAIN "wesnoth-lib"
15 
17 
18 #include "chat_log.hpp"
19 #include "font/text_formatting.hpp"
20 #include "formatter.hpp"
21 #include "game_config.hpp"
22 #include "gettext.hpp"
25 #include "gui/widgets/button.hpp"
26 #include "gui/widgets/chatbox.hpp"
27 #include "gui/widgets/drawing.hpp"
29 #include "gui/widgets/image.hpp"
30 #include "gui/widgets/listbox.hpp"
31 #include "gui/widgets/label.hpp"
32 #include "gui/widgets/settings.hpp"
33 #include "gui/widgets/slider.hpp"
38 #include "mp_ui_alerts.hpp"
39 #include "units/types.hpp"
40 #include "wesnothd_connection.hpp"
41 
42 namespace gui2
43 {
44 namespace dialogs
45 {
46 
47 REGISTER_DIALOG(mp_staging)
48 
49 mp_staging::mp_staging(ng::connect_engine& connect_engine, mp::lobby_info& lobby_info, wesnothd_connection* connection)
50  : connect_engine_(connect_engine)
51  , ai_algorithms_(ai::configuration::get_available_ais())
52  , lobby_info_(lobby_info)
53  , network_connection_(connection)
54  , update_timer_(0)
55  , state_changed_(false)
56  , team_tree_map_()
57  , side_tree_map_()
58  , player_list_(nullptr)
59 {
60  set_show_even_without_video(true);
61 
62  assert(!ai_algorithms_.empty());
63 }
64 
66 {
67  if(update_timer_ != 0) {
69  update_timer_ = 0;
70  }
71 }
72 
74 {
75  window.set_enter_disabled(true);
76  window.set_escape_disabled(true);
77 
78  //
79  // Set title and status widget states
80  //
81  label& title = find_widget<label>(&window, "title", false);
82  title.set_label((formatter() << title.get_label() << " " << font::unicode_em_dash << " " << connect_engine_.scenario()["name"].t_str()).str());
83 
85 
86  //
87  // Set up teams
88  //
90  tree_view& tree = find_widget<tree_view>(&window, "side_list", false);
91  static const std::map<std::string, string_map> empty_map;
92 
93  std::map<std::string, string_map> tree_data;
94  string_map tree_item;
95 
96  tree_item["label"] = (formatter() << _("Team:") << " " << t_string::from_serialized(team.user_team_name)).str();
97  tree_data.emplace("tree_view_node_label", tree_item);
98 
99  tree_view_node& team_node = tree.add_node("team_header", tree_data);
100  team_node.add_sibling("side_spacer", empty_map);
101 
102  team_tree_map_[team.team_name] = &team_node;
103  }
104 
105  //
106  // Set up sides list
107  // This must be after setting up teams because add_side_node() uses team_tree_map_
108  //
109  for(const auto& side : connect_engine_.side_engines()) {
110  if(side->allow_player() || game_config::debug) {
111  add_side_node(window, side);;
112  }
113  }
114 
115  //
116  // Initialize chatbox and game rooms
117  //
118  chatbox& chat = find_widget<chatbox>(&window, "chat", false);
119 
121 
122  if(network_connection_) {
124  }
125 
126  chat.room_window_open(N_("this game"), true, false);
127  chat.active_window_changed();
128  chat.load_log(default_chat_log, false);
129 
130  //
131  // Set up player list
132  //
133  player_list_.reset(new player_list_helper(&window));
134 
135  //
136  // Set up the network handling
137  //
138  update_timer_ = add_timer(game_config::lobby_network_timer, std::bind(&mp_staging::network_handler, this, std::ref(window)), true);
139 
140  //
141  // Set up the Lua plugin context
142  //
143  plugins_context_.reset(new plugins_context("Multiplayer Staging"));
144 
145  plugins_context_->set_callback("launch", [&window](const config&) { window.set_retval(retval::OK); }, false);
146  plugins_context_->set_callback("quit", [&window](const config&) { window.set_retval(retval::CANCEL); }, false);
147  plugins_context_->set_callback("chat", [&chat](const config& cfg) { chat.send_chat_message(cfg["message"], false); }, true);
148 }
149 
151 {
152  int position = 0;
153  for(const auto& side_engine : connect_engine_.side_engines()) {
154  if(side->team() == side_engine->team() && side->index() > side_engine->index()) {
155  ++position;
156  }
157  }
158 
159  return position;
160 }
161 
163 {
164  std::map<std::string, string_map> data;
166 
167  item["label"] = std::to_string(side->index() + 1);
168  data.emplace("side_number", item);
169 
170  // TODO: don't hardcode magenta?
171  item["label"] = "units/unknown-unit.png~RC(magenta>" + side->color_id() + ")";
172  data.emplace("leader_image", item);
173 
174  item["label"] = "icons/icon-random.png";
175  data.emplace("leader_gender", item);
176 
177  tree_view_node& node = team_tree_map_[side->team_name()]->add_child("side_panel", data, get_side_node_position(side));
178 
179  side_tree_map_[side] = &node;
180 
181  grid& row_grid = node.get_grid();
182 
183  update_leader_display(side, row_grid);
184 
185  // Status variables
186  const bool fls = connect_engine_.force_lock_settings();
187  const bool ums = connect_engine_.params().use_map_settings;
188 
189  const bool lock_gold = side->cfg()["gold_lock"].to_bool(fls);
190  const bool lock_income = side->cfg()["income_lock"].to_bool(fls);
191  const bool lock_team = side->cfg()["team_lock"].to_bool(fls);
192  const bool lock_color = side->cfg()["color_lock"].to_bool(fls);
193 
194  const bool saved_game = connect_engine_.params().saved_game == mp_game_settings::SAVED_GAME_MODE::MIDGAME;
195 
196  //
197  // AI Algorithm
198  //
199  int selection = 0;
200 
201  // We use an index-based loop in order to get the index of the selected option
202  std::vector<config> ai_options;
203  // If this is loading a saved game, we add an option at the beginning of the menu.
204  // This results in a mismatch between the indices of ai_options and ai_algorithms_
205  // that we need to account for later.
206  if(saved_game) {
207  ai_options.emplace_back("label", "Keep saved AI");
208  }
209  for(unsigned i = 0; i < ai_algorithms_.size(); ++i) {
210  ai_options.emplace_back("label", ai_algorithms_[i]->text);
211 
212  if(ai_algorithms_[i]->id == side->ai_algorithm()) {
213  selection = i;
214  }
215  }
216 
217  menu_button& ai_selection = find_widget<menu_button>(&row_grid, "ai_controller", false);
218 
219  ai_selection.set_values(ai_options, selection);
220 
221  connect_signal_notify_modified(ai_selection,
222  std::bind(&mp_staging::on_ai_select, this, side, std::ref(ai_selection), saved_game));
223 
224  on_ai_select(side, ai_selection, saved_game);
225  //
226  // Controller
227  //
228  std::vector<config> controller_names;
229  for(const auto& controller : side->controller_options()) {
230  controller_names.emplace_back("label", controller.second);
231  }
232 
233  menu_button& controller_selection = find_widget<menu_button>(&row_grid, "controller", false);
234 
235  controller_selection.set_values(controller_names, side->current_controller_index());
236  controller_selection.set_active(controller_names.size() > 1);
237 
238  connect_signal_notify_modified(controller_selection,
239  std::bind(&mp_staging::on_controller_select, this, side, std::ref(row_grid)));
240 
241  on_controller_select(side, row_grid);
242 
243  //
244  // Leader controls
245  //
246  button& leader_select = find_widget<button>(&row_grid, "select_leader", false);
247 
248  //todo: shouldn't this also be disabled when the flg settings are locked.
249  leader_select.set_active(!saved_game);
250 
251  connect_signal_mouse_left_click(leader_select,
252  std::bind(&mp_staging::select_leader_callback, this, side, std::ref(row_grid)));
253 
254  //
255  // Team
256  //
257  std::vector<config> team_names;
258  unsigned initial_team_selection = 0;
259 
260  for(unsigned i = 0; i < connect_engine_.team_data().size(); ++i) {
262 
263  if(!tdata.is_player_team && !game_config::debug) {
264  continue;
265  }
266 
267  config entry;
268  entry["label"] = t_string::from_serialized(tdata.user_team_name);
269 
270  // Since we're not necessarily displaying every every team, we need to store the
271  // index a displayed team has in the connect_engine's team_data vector. This is
272  // then utilized in the click callback.
273  entry["team_index"] = i;
274 
275  team_names.push_back(std::move(entry));
276 
277  // Since, again, every team might not be displayed, and side_engine::team() returns
278  // an index into the team_data vector, get an initial selection index for the menu
279  // adjusted for the displayed named.
280  if(side->team() == i) {
281  initial_team_selection = team_names.size() - 1;
282  }
283  }
284 
285  menu_button& team_selection = find_widget<menu_button>(&row_grid, "side_team", false);
286 
287  team_selection.set_values(team_names, initial_team_selection);
288  //todo: shouldn't this also be disabled when team settings are locked.
289  team_selection.set_active(!saved_game);
290 
291  connect_signal_notify_modified(team_selection,
292  std::bind(&mp_staging::on_team_select, this, std::ref(window), side, std::ref(team_selection)));
293 
294  //
295  // Colors
296  //
297  std::vector<config> color_options;
298  for(const auto& color : side->color_options()) {
299  color_options.emplace_back(
300  "label", font::get_color_string_pango(color),
301  "icon", (formatter() << "misc/status.png~RC(magenta>" << color << ")").str()
302  );
303  }
304 
305  menu_button& color_selection = find_widget<menu_button>(&row_grid, "side_color", false);
306 
307  color_selection.set_values(color_options, side->color());
308  color_selection.set_active(!saved_game);
309  color_selection.set_use_markup(true);
310 
311  connect_signal_notify_modified(color_selection,
312  std::bind(&mp_staging::on_color_select, this, side, std::ref(row_grid)));
313 
314  //
315  // Gold and Income
316  //
317  const auto slider_setup_helper = [](slider& slider, const int value) {
318  // For the gold and income sliders, the usual min and max values are set in
319  // the dialog WML. However, if a side specifies a value out of that range,
320  // we adjust the bounds to accommodate it.
321  slider.set_value_range(
322  std::min(value, slider.get_minimum_value()),
323  std::max(value, slider.get_maximum_value())
324  );
325 
326  slider.set_value(value);
327  };
328 
329  slider& slider_gold = find_widget<slider>(&row_grid, "side_gold_slider", false);
330  slider_setup_helper(slider_gold, side->gold());
331 
332  connect_signal_notify_modified(slider_gold, std::bind(
333  &mp_staging::on_side_slider_change<&ng::side_engine::set_gold>, this, side, std::ref(slider_gold)));
334 
335  slider& slider_income = find_widget<slider>(&row_grid, "side_income_slider", false);
336  slider_setup_helper(slider_income, side->income());
337 
338  connect_signal_notify_modified(slider_income, std::bind(
339  &mp_staging::on_side_slider_change<&ng::side_engine::set_income>, this, side, std::ref(slider_income)));
340 
341  // TODO: maybe display the saved values
342  if(saved_game) {
345  }
346 
347  //
348  // Gold, income, team, and color are only suggestions unless explicitly locked
349  //
350  if(!saved_game && ums) {
351  team_selection.set_active(!lock_team);
352  color_selection.set_active(!lock_color);
353 
354  slider_gold.set_active(!lock_gold);
355  slider_income.set_active(!lock_income);
356  }
357 }
358 
360 {
361  menu_button& ai_selection = find_widget<menu_button>(&row_grid, "ai_controller", false);
362  menu_button& controller_selection = find_widget<menu_button>(&row_grid, "controller", false);
363 
364  if(side->controller_changed(controller_selection.get_value())) {
366 
368  }
369 }
370 
372 {
373  // If this is a saved game, we need to reduce the index by one, to account for
374  // the "Keep saved AI" option having been added to the computer player menu
375  int i = ai_menu.get_value();
376  if(saved_game) {
377  i--;
378  }
379 
380  if(i < 0) {
381  side->set_ai_algorithm("use_saved");
382  } else {
383  side->set_ai_algorithm(ai_algorithms_[i]->id);
384  }
385 
387 }
388 
390 {
391  side->set_color(find_widget<menu_button>(&row_grid, "side_color", false).get_value());
392 
393  update_leader_display(side, row_grid);
394 
396 }
397 
399 {
400  // Since we're not necessarily displaying every every team in the menu, we can't just
401  // use the selected index to set a side's team. Instead, we grab the index we stored
402  // in add_side_node from the selected config, which should correspond to the
403  // appropriate entry in the connect_engine's team name vector.
404  const unsigned team_index = team_menu.get_value_config()["team_index"].to_unsigned();
405 
406  if(team_index == side->team()) {
407  return;
408  }
409 
410  side->set_team(team_index);
411 
412  // First, remove the node from the tree
413  auto node = find_widget<tree_view>(&window, "side_list", false).remove_node(side_tree_map_[side]);
414 
415  // Then add a new node as a child to the appropriate team's node
416  team_tree_map_[side->team_name()]->add_child(std::move(node.first), get_side_node_position(side));
417 
419 }
420 
422 {
423  if(gui2::dialogs::faction_select::execute(side->flg(), side->color_id(), side->index() + 1)) {
424  update_leader_display(side, row_grid);
425 
427  }
428 }
429 
430 template<void(ng::side_engine::*fptr)(int)>
432 {
433  ((*side).*fptr)(slider.get_value());
434 
436 }
437 
439 {
440  const std::string current_faction = side->flg().current_faction()["name"];
441 
442  // BIG FAT TODO: get rid of this shitty "null" string value in the FLG manager
443  std::string current_leader = side->flg().current_leader() != "null" ? side->flg().current_leader() : font::unicode_em_dash;
444  const std::string current_gender = side->flg().current_gender() != "null" ? side->flg().current_gender() : font::unicode_em_dash;
445 
446  // Sprite
447  std::string new_image;
448 
449  if(side->flg().is_random_faction() || current_leader == "random") {
450  new_image = ng::random_enemy_picture;
451  }
452 
453  if(const unit_type* ut = unit_types.find(current_leader)) {
454  const unit_type& type = ut->get_gender_unit_type(current_gender);
455 
456  new_image = formatter() << type.image() << "~RC(magenta>" << side->color_id() << ")";
457 
458  // We don't need the unit type id anymore, and can now replace this variable with the type name
459  current_leader = type.type_name();
460  }
461 
462  find_widget<drawing>(&row_grid, "leader_image", false).set_label(new_image);
463 
464  // Faction and leader
465  if(!side->cfg()["name"].empty()) {
466  current_leader = formatter() << side->cfg()["name"] << " (<i>" << current_leader << "</i>)";
467  }
468 
469  find_widget<label>(&row_grid, "leader_type", false).set_label(current_leader);
470  find_widget<label>(&row_grid, "leader_faction", false).set_label("<span color='#a69275'>" + current_faction + "</span>");
471 
472  // Gender
473  if(current_gender != font::unicode_em_dash) {
474  const std::string gender_icon = formatter() << "icons/icon-" << current_gender << ".png";
475 
476  image& icon = find_widget<image>(&row_grid, "leader_gender", false);
477  icon.set_label(gender_icon);
478  }
479 }
480 
482 {
483  find_widget<label>(&window, "status_label", false).set_label(
485  ? _("Waiting for players to join...")
486  : _("Waiting for players to choose factions...")
487  );
488 
489  find_widget<button>(&window, "ok", false).set_active(connect_engine_.can_start_game());
490 }
491 
493 {
494  // First, send off any changes if they've been accumulated
495  if(state_changed_) {
497  }
498 
499  // Next, check for any incoming changes
500  config data;
502  return;
503  }
504 
505  // Update chat
506  find_widget<chatbox>(&window, "chat", false).process_network_data(data);
507 
508  // TODO: why is this needed...
509  const bool was_able_to_start = connect_engine_.can_start_game();
510 
511  bool quit_signal_received;
512  std::tie(quit_signal_received, std::ignore) = connect_engine_.process_network_data(data);
513 
514  if(quit_signal_received) {
515  window.set_retval(retval::CANCEL);
516  }
517 
518  // Update side leader displays
519  // This is basically only needed when a new player joins and selects their faction
520  for(auto& tree_entry : side_tree_map_) {
521  ng::side_engine_ptr side = tree_entry.first;
522 
523  grid& row_grid = tree_entry.second->get_grid();
524 
525  update_leader_display(side, row_grid);
526 
527  std::vector<config> controller_names;
528  for(const auto& controller : side->controller_options()) {
529  controller_names.emplace_back("label", controller.second);
530  }
531 
532  menu_button& controller_selection = find_widget<menu_button>(&row_grid, "controller", false);
533 
534  controller_selection.set_values(controller_names, side->current_controller_index());
535  controller_selection.set_active(controller_names.size() > 1);
536  }
537 
538  // Update player list
539  if(data.has_child("user")) {
540  player_list_->update_list(data.child_range("user"));
541  }
542 
543  // Update status label and buttons
545 
546  if(!was_able_to_start && connect_engine_.can_start_game()) {
548  }
549 
550  state_changed_ = false;
551 }
552 
554 {
555  if(update_timer_ != 0) {
557  update_timer_ = 0;
558  }
559 
560  if(window.get_retval() == retval::OK) {
562  } else {
564  }
565 }
566 
567 } // namespace dialogs
568 } // namespace gui2
void active_window_changed()
Definition: chatbox.cpp:110
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
void ready_for_start()
void update_status_label_and_buttons(window &window)
Definition: mp_staging.cpp:481
const ::config & get_value_config() const
Returns the entire config object for the selected row.
Definition: menu_button.hpp:79
void set_lobby_info(mp::lobby_info &i)
Definition: chatbox.hpp:87
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1267
Simple push button.
Definition: menu_button.hpp:41
int get_side_node_position(ng::side_engine_ptr side) const
Find an appropriate position to insert a side node.
Definition: mp_staging.cpp:150
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:412
bool force_lock_settings() const
child_itors child_range(config_key_type key)
Definition: config.cpp:362
ng::connect_engine & connect_engine_
Definition: mp_staging.hpp:84
unit_type_data unit_types
Definition: types.cpp:1525
void set_escape_disabled(const bool escape_disabled)
Disable the escape key.
Definition: window.hpp:300
Label showing a text.
Definition: label.hpp:32
bool receive_data(config &result)
const std::vector< team_data_pod > & team_data() const
void update_and_send_diff(bool update_time_of_day=false)
A single unit type that the player may recruit.
Definition: types.hpp:42
Generic file dialog.
Definition: field-fwd.hpp:22
Pubic entry points for the MP workflow.
Definition: lobby_data.cpp:49
virtual void set_label(const t_string &label)
virtual void set_active(const bool active) override
See styled_widget::set_active.
Base container class.
Definition: grid.hpp:30
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
virtual unsigned get_value() const override
Inherited from selectable_item.
Definition: menu_button.hpp:64
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
void set_value_range(int min_value, int max_value)
Definition: slider.cpp:254
void update_leader_display(ng::side_engine_ptr side, grid &row_grid)
Definition: mp_staging.cpp:438
virtual int get_maximum_value() const override
Inherited from integer_selector.
Definition: slider.hpp:65
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:248
std::vector< side_engine_ptr > & side_engines()
This file contains the settings handling of the widget library.
std::ostringstream wrapper.
Definition: formatter.hpp:38
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:135
std::unique_ptr< plugins_context > plugins_context_
void set_visible(const visibility visible)
Definition: widget.cpp:473
unsigned lobby_network_timer
Definition: game_config.cpp:87
std::unique_ptr< player_list_helper > player_list_
Definition: mp_staging.hpp:99
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:233
void on_controller_select(ng::side_engine_ptr side, grid &row_grid)
Definition: mp_staging.cpp:359
A class that represents a TCP/IP connection to the wesnothd server.
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
Definition: chatbox.cpp:243
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
Definition: chatbox.cpp:95
const mp_game_settings & params() const
void set_values(const std::vector<::config > &values, unsigned selected=0)
virtual void set_use_markup(bool use_markup)
void on_side_slider_change(ng::side_engine_ptr side, slider &slider)
Definition: mp_staging.cpp:431
virtual void pre_show(window &window) override
Inherited from modal_dialog.
Definition: mp_staging.cpp:73
mp::lobby_info & lobby_info_
Definition: mp_staging.hpp:88
Various uncategorised dialogs.
int get_retval()
Definition: window.hpp:371
std::vector< ai::description * > ai_algorithms_
Definition: mp_staging.hpp:86
void network_handler(window &window)
Definition: mp_staging.cpp:492
std::size_t i
Definition: function.cpp:933
wesnothd_connection * network_connection_
Definition: mp_staging.hpp:90
void select_leader_callback(ng::side_engine_ptr side, grid &row_grid)
Definition: mp_staging.cpp:421
The user set the widget invisible, that means:
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
std::size_t add_timer(const uint32_t interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:126
static t_string from_serialized(const std::string &string)
Definition: tstring.hpp:149
std::string get_color_string_pango(const std::string &id)
Returns the name of a color range, colored with its own color.
const bool & debug
#define N_(String)
Definition: gettext.hpp:99
static const std::string controller_names[]
virtual int get_value() const override
Inherited from integer_selector.
Definition: slider.hpp:53
std::shared_ptr< side_engine > side_engine_ptr
const std::string random_enemy_picture("units/random-dice.png")
void on_ai_select(ng::side_engine_ptr side, menu_button &ai_menu, const bool saved_game)
Definition: mp_staging.cpp:371
void add_side_node(window &window, ng::side_engine_ptr side)
Definition: mp_staging.cpp:162
std::map< std::string, tree_view_node * > team_tree_map_
Definition: mp_staging.hpp:96
const std::string & image() const
Definition: types.hpp:161
const t_string & get_label() const
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:62
The user sets the widget visible, that means:
virtual void post_show(window &window) override
Inherited from modal_dialog.
Definition: mp_staging.cpp:553
The user sets the widget hidden, that means:
A slider.
Definition: slider.hpp:33
const std::string unicode_em_dash
Definition: constants.cpp:40
std::map< std::string, chatroom_log > default_chat_log
Definition: chat_log.cpp:16
void set_wesnothd_connection(wesnothd_connection &c)
Definition: chatbox.hpp:92
this module manages the cache of images.
Simple push button.
Definition: button.hpp:35
virtual void set_value(int value) override
Inherited from integer_selector.
Definition: slider.cpp:86
tree_view_node & add_sibling(const std::string &id, const std::map< std::string, string_map > &data)
Adds a sibbling for a node at the end of the list.
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: menu_button.cpp:74
void on_color_select(ng::side_engine_ptr side, grid &row_grid)
Definition: mp_staging.cpp:389
Dialog was closed with the OK button.
Definition: retval.hpp:34
bool can_start_game() const
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void on_team_select(window &window, ng::side_engine_ptr side, menu_button &team_menu)
Definition: mp_staging.cpp:398
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
std::map< ng::side_engine_ptr, tree_view_node * > side_tree_map_
Definition: mp_staging.hpp:97
lobby_chat_window * room_window_open(const std::string &room, const bool open_new, const bool allow_close=true)
Check if a room window for "room" is open, if open_new is true then it will be created if not found...
Definition: chatbox.cpp:383
virtual int get_minimum_value() const override
Inherited from integer_selector.
Definition: slider.hpp:59
const std::string & team_name() const
Definition: team.hpp:296
bool sides_available() const
const t_string & user_team_name() const
Definition: team.hpp:297
tree_view_node & add_node(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Definition: tree_view.cpp:61
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
std::pair< bool, bool > process_network_data(const config &data)
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:167
void set_enter_disabled(const bool enter_disabled)
Disable the enter key.
Definition: window.hpp:287