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));
177 filter.on_modified([
this](
const auto&) { on_filter_change<text_box>(
"game_filter",
true); });
185 std::vector<config> game_types;
187 game_types.emplace_back(
"label", type_info.second);
190 if(game_types.empty()) {
195 menu_button& game_menu_button = find_widget<menu_button>(
"game_types");
198 auto get_initial_type_index = [
this]()->
int {
200 return info.first == *level_type::get_enum(prefs::get().mp_level_type());
210 game_menu_button.
set_values(game_types, get_initial_type_index());
218 mod_list_ = &find_widget<listbox>(
"mod_list");
225 item[
"label"] = mod->name;
226 data.emplace(
"mod_name", item);
234 if(
std::find(activemods.begin(), activemods.end(), mod->id) != activemods.end()) {
252 std::vector<config> era_names;
254 era_names.emplace_back(
"label", era->name,
"tooltip", era->description);
257 if(era_names.empty()) {
268 if(era_selection >= 0) {
279 menu_button& rfm_menu_button = find_widget<menu_button>(
"random_faction_mode");
290 bind_status_label<slider>(
this,
turns_->
id());
291 bind_status_label<slider>(
this,
gold_->
id());
292 bind_status_label<slider>(
this,
support_->
id());
303 find_widget<button>(
"reset_timer_defaults"),
310 find_widget<text_box>(
"game_name").set_active(
false);
311 find_widget<text_box>(
"game_password").set_active(
false);
321 listbox& tab_bar = find_widget<listbox>(
"tab_bar");
329 find_widget<stacked_widget>(
"pager").set_find_in_all_layers(
true);
336 listbox& list = find_widget<listbox>(
"games_list");
358 #define UPDATE_ATTRIBUTE(field, convert) \
359 do { if(cfg.has_attribute(#field)) { field##_->set_widget_value(cfg[#field].convert()); } } while(false) \
380 #undef UPDATE_ATTRIBUTE
406 "id", current_level.
id(),
407 "name", current_level.
name(),
408 "icon", current_level.
icon(),
416 const std::string
id = cfg[
"id"].str();
419 "index", result.second,
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.
field_bool * shuffle_sides_
void load_game_callback()
field_integer * turn_bonus_
std::unique_ptr< ng::configure_engine > config_engine_
std::pair< level_type::type, std::string > level_type_info
void show_generator_settings()
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()
void on_mod_toggle(const std::string &id, toggle_button *sender)
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()
bool dialog_exit_hook()
Dialog exit hook to bring up the difficulty dialog when starting a campaign.
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
A widget that allows the user to input text in single line.
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.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
void set_exit_hook(exit_hook mode, const Func &hook)
Sets the window's exit hook.
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, bool floating)
Generates a Help markup tag corresponding to an image.
const int turns_max
maximum number of turns
std::size_t index(std::string_view 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.
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
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.