16 #define GETTEXT_DOMAIN "wesnoth-lib"
45 #include <boost/algorithm/string.hpp>
49 #define DBG_MP LOG_STREAM(debug, log_mp_create)
50 #define WRN_MP LOG_STREAM(warn, log_mp_create)
51 #define ERR_MP LOG_STREAM(err, log_mp_create)
63 , create_engine_(state)
66 , selected_game_index_(-1)
67 , selected_rfm_index_(-1)
68 , use_map_settings_(register_bool( "use_map_settings", true,
69 []() {
return prefs::get().mp_use_map_settings();},
70 [](
bool v) {
prefs::get().set_mp_use_map_settings(v);},
72 , fog_(register_bool(
"fog",
true,
75 , shroud_(register_bool(
"shroud",
true,
78 , start_time_(register_bool(
"random_start_time",
true,
79 []() {
return prefs::get().mp_random_start_time();},
80 [](
bool v) {
prefs::get().set_mp_random_start_time(v);}))
81 , time_limit_(register_bool(
"time_limit",
true,
83 [](
bool v) {
prefs::get().set_mp_countdown(v);},
85 , shuffle_sides_(register_bool(
"shuffle_sides",
true,
87 [](
bool v) {
prefs::get().set_shuffle_sides(v);}))
88 , observers_(register_bool(
"observers",
true,
90 [](
bool v) {
prefs::get().set_allow_observers(v);}))
91 , strict_sync_(register_bool(
"strict_sync",
true))
92 , private_replay_(register_bool(
"private_replay",
true))
93 , turns_(register_integer(
"turn_count",
true,
96 , gold_(register_integer(
"village_gold",
true,
99 , support_(register_integer(
"village_support",
true,
102 , experience_(register_integer(
"experience_modifier",
true,
105 , init_turn_limit_(register_integer(
"init_turn_limit",
true,
108 , turn_bonus_(register_integer(
"turn_bonus",
true,
111 , reservoir_(register_integer(
"reservoir",
true,
114 , action_bonus_(register_integer(
"action_bonus",
true,
118 , eras_menu_button_()
119 , local_mode_(local_mode)
122 {level_type::type::scenario,
_(
"Scenarios")},
123 {level_type::type::campaign,
_(
"Multiplayer Campaigns")},
124 {level_type::type::sp_campaign,
_(
"Singleplayer Campaigns")},
125 {level_type::type::user_map,
_(
"Custom Maps")},
126 {level_type::type::user_scenario,
_(
"Custom Scenarios")},
127 {level_type::type::random_map,
_(
"Random Maps")},
130 level_types_.erase(std::remove_if(level_types_.begin(), level_types_.end(),
131 [
this](level_type_info& type_info) {
132 return create_engine_.get_levels_by_type_unfiltered(type_info.first).empty();
133 }), level_types_.end());
135 set_show_even_without_video(
true);
137 create_engine_.init_active_mods();
139 create_engine_.get_state().clear();
140 create_engine_.get_state().classification().type = campaign_type::type::multiplayer;
143 set_allow_plugin_skip(
false);
151 find_widget<button>(
"random_map_regenerate"),
155 find_widget<button>(
"random_map_settings"),
159 find_widget<button>(
"load_game"),
174 std::bind(&mp_create_game::on_filter_change<slider>,
this,
"num_players",
true));
176 text_box& filter = find_widget<text_box>(
"game_filter");
179 std::bind(&mp_create_game::on_filter_change<text_box>,
this,
"game_filter",
true));
187 std::vector<config> game_types;
189 game_types.emplace_back(
"label", type_info.second);
192 if(game_types.empty()) {
197 menu_button& game_menu_button = find_widget<menu_button>(
"game_types");
200 auto get_initial_type_index = [
this]()->
int {
202 return info.first == *level_type::get_enum(prefs::get().mp_level_type());
212 game_menu_button.
set_values(game_types, get_initial_type_index());
220 mod_list_ = &find_widget<listbox>(
"mod_list");
227 item[
"label"] = mod->name;
228 data.emplace(
"mod_name", item);
236 if(std::find(activemods.begin(), activemods.end(), mod->id) != activemods.end()) {
254 std::vector<config> era_names;
256 era_names.emplace_back(
"label", era->name,
"tooltip", era->description);
259 if(era_names.empty()) {
270 if(era_selection >= 0) {
281 menu_button& rfm_menu_button = find_widget<menu_button>(
"random_faction_mode");
292 bind_status_label<slider>(
this,
turns_->
id());
293 bind_status_label<slider>(
this,
gold_->
id());
294 bind_status_label<slider>(
this,
support_->
id());
305 find_widget<button>(
"reset_timer_defaults"),
312 find_widget<text_box>(
"game_name").set_active(
false);
313 find_widget<text_box>(
"game_password").set_active(
false);
323 listbox& tab_bar = find_widget<listbox>(
"tab_bar");
331 find_widget<stacked_widget>(
"pager").set_find_in_all_layers(
true);
338 listbox& list = find_widget<listbox>(
"games_list");
360 #define UPDATE_ATTRIBUTE(field, convert) \
361 do { if(cfg.has_attribute(#field)) { field##_->set_widget_value(cfg[#field].convert()); } } while(false) \
382 #undef UPDATE_ATTRIBUTE
408 "id", current_level.
id(),
409 "name", current_level.
name(),
410 "icon", current_level.
icon(),
418 const std::string
id = cfg[
"id"].str();
436 DBG_MP <<
"sync_with_depcheck: start";
439 DBG_MP <<
"sync_with_depcheck: correcting era";
447 DBG_MP <<
"sync_with_depcheck: correcting scenario";
453 if(new_level_index.second != -1) {
458 auto& game_types_list = find_widget<menu_button>(
"game_types");
468 find_widget<listbox>(
"games_list").select_row(new_level_index.second);
479 DBG_MP <<
"sync_with_depcheck: correcting modifications";
484 DBG_MP <<
"sync_with_depcheck: end";
492 listbox& game_list = find_widget<listbox>(
"games_list");
508 const int selected_game = find_widget<listbox>(
"games_list").get_selected_row();
526 if(!can_select_era) {
543 const int i = find_widget<listbox>(
"tab_bar").get_selected_row();
544 find_widget<stacked_widget>(
"pager").select_layer(
i);
550 ERR_MP <<
"ignoring on_mod_toggle that is already set";
579 styled_widget& description = find_widget<styled_widget>(
"description");
581 description.
set_label(!new_description.empty() ? new_description :
_(
"No description available."));
587 const int index = find_widget<menu_button>(
"game_types").get_value();
596 listbox& list = find_widget<listbox>(
"games_list");
604 if(
type == level_type::type::campaign ||
type == level_type::type::sp_campaign) {
605 item[
"label"] =
game->icon();
606 data.emplace(
"game_icon", item);
609 item[
"label"] =
game->name();
610 data.emplace(
"game_name", item);
615 if(icon.get_label().empty()) {
622 on_filter_change<slider>(
"num_players",
false);
623 on_filter_change<text_box>(
"game_filter",
false);
626 if(level_index >= 0 && std::size_t(level_index) < list.
get_item_count()) {
631 const bool is_random_map =
type == level_type::type::random_map;
633 find_widget<button>(
"random_map_regenerate").set_active(is_random_map);
634 find_widget<button>(
"random_map_settings").set_active(is_random_map);
659 return std::distance(filtered_indices.begin(), std::find(filtered_indices.begin(), filtered_indices.end(), initial_index));
664 styled_widget& players = find_widget<styled_widget>(
"map_num_players");
665 styled_widget& map_size = find_widget<styled_widget>(
"map_size");
688 find_widget<styled_widget>(
"game_title").set_label(title);
692 case level_type::type::scenario:
693 case level_type::type::user_map:
694 case level_type::type::user_scenario:
695 case level_type::type::random_map: {
698 assert(current_scenario);
702 find_widget<stacked_widget>(
"minimap_stack").select_layer(0);
704 if(current_scenario->
data()[
"map_data"].
empty()) {
709 find_widget<minimap>(
"minimap").set_map_data(current_scenario->
data()[
"map_data"]);
716 case level_type::type::campaign:
717 case level_type::type::sp_campaign: {
720 assert(current_campaign);
724 const std::string
img =
formatter() << current_campaign->
data()[
"image"] <<
"~SCALE_INTO(265,265)";
726 find_widget<stacked_widget>(
"minimap_stack").select_layer(1);
727 find_widget<image>(
"campaign_image").set_image(
img);
733 players.
set_label(
VGETTEXT(
"number of players^$min to $max", {{
"min", std::to_string(p_min)}, {
"max", std::to_string(p_max)}}));
735 players.
set_label(std::to_string(p_min));
777 find_widget<button>(
"reset_timer_defaults").set_active(time_limit);
779 if(use_map_settings) {
795 if(!
load.load_multiplayer_game()) {
799 if(
load.data().cancel_orders) {
809 std::set<std::string> res;
816 return std::vector<std::string>(res.begin(), res.end());
821 std::set<std::string> val2(val.begin(), val.end());
823 std::set<std::string> res;
852 std::stringstream
msg;
854 msg <<
_(
"The selected game cannot be created.");
873 find_widget<stacked_widget>(
"pager").select_layer(-1);
905 std::vector<const config*> entry_points;
906 std::vector<std::string> entry_point_titles;
910 if(tagname ==
"scenario") {
913 const bool is_first = scenario[
"id"] == first_scenario;
915 const std::string& title = !scenario[
"new_game_title"].
empty()
916 ? scenario[
"new_game_title"]
919 entry_points.insert(is_first ? entry_points.begin() : entry_points.end(), &scenario);
920 entry_point_titles.insert(is_first ? entry_point_titles.begin() : entry_point_titles.end(), title);
925 if(entry_points.size() > 1) {
974 const std::string name = find_widget<text_box>(
"game_name").get_value();
980 const std::string password = find_widget<text_box>(
"game_password").get_value();
981 if(!password.empty()) {
A config object defines a single node in a WML file, with access to child nodes.
std::string get_tagname() const
std::string campaign
The id of the campaign being played.
static game_config_manager * get()
Abstract base class for all modal dialogs.
bool show(const unsigned auto_close_time=0)
Shows the window.
int get_retval() const
Returns the cached window exit code.
field_bool * shuffle_sides_
void load_game_callback()
field_integer * turn_bonus_
std::unique_ptr< ng::configure_engine > config_engine_
bool dialog_exit_hook(window &)
Dialog exit hook to bring up the difficulty dialog when starting a campaign.
std::pair< level_type::type, std::string > level_type_info
void show_generator_settings()
void on_mod_toggle(const std::string id, toggle_button *sender)
void display_games_of_type(level_type::type type, const std::string &level)
virtual void post_show() override
Actions to be taken after the window has been shown.
field_integer * action_bonus_
void set_active_mods(const std::vector< std::string > &val)
void show_description(const std::string &new_description)
virtual void pre_show() override
Actions to be taken before showing the window.
void sync_with_depcheck()
void update_map_settings()
field_integer * init_turn_limit_
std::unique_ptr< mp_options_helper > options_manager_
field_integer * experience_
menu_button * eras_menu_button_
void reset_timer_settings()
std::vector< level_type_info > level_types_
field_bool * strict_sync_
field_bool * private_replay_
ng::create_engine create_engine_
void on_filter_change(const std::string &id, bool do_select)
void on_random_faction_mode_select()
std::vector< std::string > get_active_mods()
int convert_to_game_filtered_index(const unsigned int initial_index)
field_bool * use_map_settings_
All fields are also in the normal field vector, but they need to be manually controlled as well so ad...
void regenerate_random_map()
field_integer * reservoir_
std::unique_ptr< plugins_context > plugins_context_
void set_single_button(bool value)
Sets whether the Cancel button should be hidden or not.
int selected_index() const
Returns the selected item index after displaying.
const std::string & id() const
void widget_set_enabled(const bool enable, const bool sync)
Enables a widget.
void set_widget_value(CT value)
Sets the value of the field.
T get_widget_value()
Gets the value of the field.
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
bool select_row(const unsigned row, const bool select=true)
Selects a row.
boost::dynamic_bitset get_rows_shown() const
Returns a list of visible rows.
void clear()
Removes all the rows in the listbox, clearing it.
unsigned get_item_count() const
Returns the number of items in the listbox.
void set_value_bool(bool value, bool fire_event=false)
bool get_value_bool() const
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
A widget that allows the user to input text in single line.
base class of top level items, the only item which needs to store the final canvases to draw on.
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
void keyboard_capture(widget *widget)
void add_to_keyboard_chain(widget *widget)
Adds the widget to the keyboard chain.
void set_exit_hook(exit_hook mode, std::function< bool(window &)> func)
Sets the window's exit hook.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
@ on_ok
Run hook only if result is OK.
int find_extra_by_id(const MP_EXTRA extra_type, const std::string &id) const
std::vector< std::size_t > get_filtered_level_indices(level_type::type type) const
bool toggle_mod(const std::string &id, bool force=false)
void set_current_era_index(const std::size_t index, bool force=false)
std::string select_campaign_difficulty(int set_value=-1)
select_campaign_difficulty
bool generator_has_settings() const
std::vector< std::string > & active_mods()
bool current_level_has_side_data()
Returns true if the current level has one or more [side] tags.
bool generator_assigned() const
level_type::type current_level_type() const
std::vector< extras_metadata_ptr > & get_extras_by_type(const MP_EXTRA extra_type)
const std::vector< extras_metadata_ptr > & get_const_extras_by_type(const MP_EXTRA extra_type) const
void apply_level_filter(const std::string &name)
void prepare_for_new_level()
const depcheck::manager & dependency_manager() const
const extras_metadata & current_era() const
void set_current_level_type(const level_type::type type)
std::pair< level_type::type, int > find_level_by_id(const std::string &id) const
bool is_campaign() const
Wrapper to simplify the is-type-campaign-or-sp-campaign check.
void prepare_for_campaign(const std::string &difficulty="")
std::vector< level_ptr > get_levels_by_type_unfiltered(level_type::type type) const
const mp_game_settings & get_parameters()
void prepare_for_saved_game()
void set_current_level(const std::size_t index)
void generator_user_config()
void prepare_for_era_and_mods()
std::size_t current_era_index() const
void init_generated_level_data()
void prepare_for_scenario()
level & current_level() const
const std::string & get_scenario() const
Returns the selected scenario.
int get_era_index() const
Returns the selected era.
bool is_modification_active(int index) const
Tells whether a certain mod is activated.
const std::vector< std::string > & get_modifications() const
Returns the enabled modifications.
Base class for all level type classes.
const config & data() const
virtual bool can_launch_game() const =0
virtual std::string id() const
virtual std::string name() const
virtual void set_metadata()=0
virtual bool allow_era_choice() const
virtual std::string icon() const
virtual std::string description() const
std::string map_size() const
int countdown_init_time()
void set_countdown_reservoir_time(int value)
void set_village_gold(int value)
void clear_countdown_init_time()
void set_countdown_action_bonus(int value)
void set_xp_modifier(int value)
int countdown_action_bonus()
void set_countdown_turn_bonus(int value)
void set_village_support(int value)
void clear_countdown_turn_bonus()
void set_countdown_init_time(int value)
void clear_countdown_reservoir_time()
const std::vector< std::string > & modifications(bool mp=true)
void set_modifications(const std::vector< std::string > &value, bool mp=true)
int countdown_reservoir_time()
int countdown_turn_bonus()
void clear_countdown_action_bonus()
game_classification & classification()
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
void set_scenario(config scenario)
static void expand_map_file(config &scenario)
reads scenario["map_file"]
The class for loading a savefile.
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed.
static std::string _(const char *str)
Standard logging facilities (interface).
General settings and defaults for scenarios.
static lg::log_domain log_mp_create("mp/create")
#define UPDATE_ATTRIBUTE(field, convert)
const std::string unicode_em_dash
Game configuration data as global variables.
REGISTER_DIALOG(editor_edit_unit)
static const int LOAD_GAME
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
std::map< std::string, widget_item > widget_data
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
std::map< std::string, t_string > widget_item
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
@ OK
Dialog was closed with the OK button.
@ CANCEL
Dialog was closed with the CANCEL button.
Functions to load and save images from/to disk.
std::string img(const std::string &src, const std::string &align, const bool floating)
const int turns_max
maximum number of turns
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
string_enums::enum_base< random_faction_mode_defines > random_faction_mode
Base class for all the errors encountered by the engine.
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.