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")},
131 return create_engine_.get_levels_by_type_unfiltered(type_info.first).empty();
134 set_show_even_without_video(
true);
136 create_engine_.init_active_mods();
138 create_engine_.get_state().clear();
139 create_engine_.get_state().classification().type = campaign_type::type::multiplayer;
142 set_allow_plugin_skip(
false);
150 find_widget<button>(
"random_map_regenerate"),
154 find_widget<button>(
"random_map_settings"),
158 find_widget<button>(
"load_game"),
173 std::bind(&mp_create_game::on_filter_change<slider>,
this,
"num_players",
true));
175 text_box& filter = find_widget<text_box>(
"game_filter");
178 std::bind(&mp_create_game::on_filter_change<text_box>,
this,
"game_filter",
true));
186 std::vector<config> game_types;
188 game_types.emplace_back(
"label", type_info.second);
191 if(game_types.empty()) {
196 menu_button& game_menu_button = find_widget<menu_button>(
"game_types");
199 auto get_initial_type_index = [
this]()->
int {
201 return info.first == *level_type::get_enum(prefs::get().mp_level_type());
211 game_menu_button.
set_values(game_types, get_initial_type_index());
219 mod_list_ = &find_widget<listbox>(
"mod_list");
226 item[
"label"] = mod->name;
227 data.emplace(
"mod_name", item);
235 if(std::find(activemods.begin(), activemods.end(), mod->id) != activemods.end()) {
253 std::vector<config> era_names;
255 era_names.emplace_back(
"label", era->name,
"tooltip", era->description);
258 if(era_names.empty()) {
269 if(era_selection >= 0) {
280 menu_button& rfm_menu_button = find_widget<menu_button>(
"random_faction_mode");
291 bind_status_label<slider>(
this,
turns_->
id());
292 bind_status_label<slider>(
this,
gold_->
id());
293 bind_status_label<slider>(
this,
support_->
id());
304 find_widget<button>(
"reset_timer_defaults"),
311 find_widget<text_box>(
"game_name").set_active(
false);
312 find_widget<text_box>(
"game_password").set_active(
false);
322 listbox& tab_bar = find_widget<listbox>(
"tab_bar");
330 find_widget<stacked_widget>(
"pager").set_find_in_all_layers(
true);
337 listbox& list = find_widget<listbox>(
"games_list");
359 #define UPDATE_ATTRIBUTE(field, convert) \
360 do { if(cfg.has_attribute(#field)) { field##_->set_widget_value(cfg[#field].convert()); } } while(false) \
381 #undef UPDATE_ATTRIBUTE
407 "id", current_level.
id(),
408 "name", current_level.
name(),
409 "icon", current_level.
icon(),
417 const std::string
id = cfg[
"id"].str();
435 DBG_MP <<
"sync_with_depcheck: start";
438 DBG_MP <<
"sync_with_depcheck: correcting era";
446 DBG_MP <<
"sync_with_depcheck: correcting scenario";
452 if(new_level_index.second != -1) {
457 auto& game_types_list = find_widget<menu_button>(
"game_types");
467 find_widget<listbox>(
"games_list").select_row(new_level_index.second);
478 DBG_MP <<
"sync_with_depcheck: correcting modifications";
483 DBG_MP <<
"sync_with_depcheck: end";
491 listbox& game_list = find_widget<listbox>(
"games_list");
507 const int selected_game = find_widget<listbox>(
"games_list").get_selected_row();
525 if(!can_select_era) {
542 const int i = find_widget<listbox>(
"tab_bar").get_selected_row();
543 find_widget<stacked_widget>(
"pager").select_layer(
i);
549 ERR_MP <<
"ignoring on_mod_toggle that is already set";
578 styled_widget& description = find_widget<styled_widget>(
"description");
580 description.
set_label(!new_description.empty() ? new_description :
_(
"No description available."));
586 const int index = find_widget<menu_button>(
"game_types").get_value();
595 listbox& list = find_widget<listbox>(
"games_list");
603 if(
type == level_type::type::campaign ||
type == level_type::type::sp_campaign) {
604 item[
"label"] =
game->icon();
605 data.emplace(
"game_icon", item);
608 item[
"label"] =
game->name();
609 data.emplace(
"game_name", item);
614 if(icon.get_label().empty()) {
621 on_filter_change<slider>(
"num_players",
false);
622 on_filter_change<text_box>(
"game_filter",
false);
625 if(level_index >= 0 && std::size_t(level_index) < list.
get_item_count()) {
630 const bool is_random_map =
type == level_type::type::random_map;
632 find_widget<button>(
"random_map_regenerate").set_active(is_random_map);
633 find_widget<button>(
"random_map_settings").set_active(is_random_map);
658 return std::distance(filtered_indices.begin(), std::find(filtered_indices.begin(), filtered_indices.end(), initial_index));
663 styled_widget& players = find_widget<styled_widget>(
"map_num_players");
664 styled_widget& map_size = find_widget<styled_widget>(
"map_size");
687 find_widget<styled_widget>(
"game_title").set_label(title);
691 case level_type::type::scenario:
692 case level_type::type::user_map:
693 case level_type::type::user_scenario:
694 case level_type::type::random_map: {
697 assert(current_scenario);
701 find_widget<stacked_widget>(
"minimap_stack").select_layer(0);
703 if(current_scenario->
data()[
"map_data"].
empty()) {
708 find_widget<minimap>(
"minimap").set_map_data(current_scenario->
data()[
"map_data"]);
715 case level_type::type::campaign:
716 case level_type::type::sp_campaign: {
719 assert(current_campaign);
723 const std::string
img =
formatter() << current_campaign->
data()[
"image"] <<
"~SCALE_INTO(265,265)";
725 find_widget<stacked_widget>(
"minimap_stack").select_layer(1);
726 find_widget<image>(
"campaign_image").set_image(
img);
732 players.
set_label(
VGETTEXT(
"number of players^$min to $max", {{
"min", std::to_string(p_min)}, {
"max", std::to_string(p_max)}}));
734 players.
set_label(std::to_string(p_min));
776 find_widget<button>(
"reset_timer_defaults").set_active(time_limit);
778 if(use_map_settings) {
794 if(!
load.load_multiplayer_game()) {
798 if(
load.data().cancel_orders) {
808 std::set<std::string> res;
815 return std::vector<std::string>(res.begin(), res.end());
820 std::set<std::string> val2(val.begin(), val.end());
822 std::set<std::string> res;
851 std::stringstream
msg;
853 msg <<
_(
"The selected game cannot be created.");
872 find_widget<stacked_widget>(
"pager").select_layer(-1);
904 std::vector<const config*> entry_points;
905 std::vector<std::string> entry_point_titles;
909 if(tagname ==
"scenario") {
912 const bool is_first = scenario[
"id"] == first_scenario;
914 const std::string& title = !scenario[
"new_game_title"].
empty()
915 ? scenario[
"new_game_title"]
918 entry_points.insert(is_first ? entry_points.begin() : entry_points.end(), &scenario);
919 entry_point_titles.insert(is_first ? entry_point_titles.begin() : entry_point_titles.end(), title);
924 if(entry_points.size() > 1) {
973 const std::string name = find_widget<text_box>(
"game_name").get_value();
979 const std::string password = find_widget<text_box>(
"game_password").get_value();
980 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
std::chrono::seconds countdown_turn_bonus()
void set_countdown_reservoir_time(const std::chrono::seconds &value)
void set_village_gold(int value)
void clear_countdown_init_time()
void set_xp_modifier(int value)
std::chrono::seconds countdown_init_time()
void set_countdown_turn_bonus(const std::chrono::seconds &value)
void set_village_support(int value)
std::chrono::seconds countdown_action_bonus()
void clear_countdown_turn_bonus()
void clear_countdown_reservoir_time()
const std::vector< std::string > & modifications(bool mp=true)
std::chrono::seconds countdown_reservoir_time()
void set_modifications(const std::vector< std::string > &value, bool mp=true)
void set_countdown_init_time(const std::chrono::seconds &value)
void set_countdown_action_bonus(const std::chrono::seconds &value)
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.
void erase_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::remove_if on a container.
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.