The Battle for Wesnoth  1.19.5+dev
create_engine.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2024
3  by Andrius Silinskas <silinskas.andrius@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "filesystem.hpp"
19 #include "game_config_manager.hpp"
24 #include "log.hpp"
25 #include "map/exception.hpp"
26 #include "map/map.hpp"
27 #include "saved_game.hpp"
28 #include "side_controller.hpp"
29 #include "wml_exception.hpp"
30 
31 #include "serialization/chrono.hpp"
33 #include "serialization/parser.hpp"
34 
35 #include <sstream>
36 
37 static lg::log_domain log_config("config");
38 #define ERR_CF LOG_STREAM(err, log_config)
39 
40 static lg::log_domain log_mp_create_engine("mp/create/engine");
41 #define WRN_MP LOG_STREAM(warn, log_mp_create_engine)
42 #define DBG_MP LOG_STREAM(debug, log_mp_create_engine)
43 
44 namespace ng {
45 
47  : data_(data)
48 {
49 }
50 
52  : level(data)
53  , map_()
54  , map_hash_()
55  , num_players_(0)
56 {
57  set_metadata();
58 }
59 
61 {
62  return map_.get() != nullptr;
63 }
64 
66 {
67  const std::string& map_data = data_["map_data"];
68 
69  try {
70  map_.reset(new gamemap(map_data));
71  } catch(const incorrect_map_format_error& e) {
72  // Set map content to nullptr, so that it fails can_launch_game()
73  map_.reset(nullptr);
74  data_["description"] = _("Map could not be loaded: ") + e.message;
75 
76  ERR_CF << "map could not be loaded: " << e.message;
77  } catch(const wml_exception& e) {
78  data_["description"] = _("Map could not be loaded.");
79 
80  ERR_CF << "map could not be loaded: " << e.dev_message;
81  }
82 
83  set_sides();
84 }
85 
86 std::string scenario::map_size() const
87 {
88  std::stringstream map_size;
89 
90  if(map_.get() != nullptr) {
91  map_size << map_->w();
93  map_size << map_->h();
94  } else {
95  map_size << _("not available.");
96  }
97 
98  return map_size.str();
99 }
100 
102 {
103  if(map_.get() != nullptr) {
104  // If there are fewer sides in the configuration than there are
105  // starting positions, then generate the additional sides
106  const int map_positions = map_->num_valid_starting_positions();
107 
108  if(!data_.has_child("side")) {
109  for(int pos = 0; pos < map_positions; ++pos) {
110  config& side = data_.add_child("side");
111  side["side"] = pos + 1;
112  side["team_name"] = "Team " + std::to_string(pos + 1);
113  side["canrecruit"] = true;
114  side["controller"] = side_controller::human;
115  }
116  }
117 
118  num_players_ = 0;
119  for(const config& scenario : data_.child_range("side")) {
120  if(scenario["allow_player"].to_bool(true)) {
121  ++num_players_;
122  }
123  }
124  }
125 }
126 
127 user_map::user_map(const config& data, const std::string& name, gamemap* map)
128  : scenario(data)
129  , name_(name)
130 {
131  if(map != nullptr) {
132  map_.reset(new gamemap(*map));
133  }
134 
135  set_metadata();
136 }
137 
139 {
140  set_sides();
141 }
142 
143 std::string user_map::description() const
144 {
145  if(!data_["description"].empty()) {
146  return data_["description"];
147  }
148 
149  // map error message
150  return _("Custom map.");
151 }
152 
154  : scenario(data)
155  , generator_data_()
156  , generate_whole_scenario_(data_.has_attribute("scenario_generation"))
157  , generator_name_(generate_whole_scenario_ ? data_["scenario_generation"] : data_["map_generation"])
158 {
159  if(!data.has_child("generator")) {
160  data_.clear();
162  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
163  data_["error_message"] = "missing [generator] tag";
164  } else {
165  generator_data_ = data.mandatory_child("generator");
166  }
167 
168  if(!data.has_attribute("scenario_generation") && !data.has_attribute("map_generation")) {
169  data_.clear();
171  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
172  data_["error_message"] = "couldn't find 'scenario_generation' or 'map_generation' attribute";
173  }
174 }
175 
177 {
179 }
180 
182  : level(data)
183  , id_(data["id"])
184  , allow_era_choice_(level::allow_era_choice())
185  , image_label_()
186  , min_players_(1)
187  , max_players_(1)
188 {
189  if(data.has_attribute("start_year")) {
190  dates_.first = utils::irdya_date::read_date(data["start_year"]);
191  if(data.has_attribute("end_year")) {
192  dates_.second = utils::irdya_date::read_date(data["end_year"]);
193  } else {
194  dates_.second = dates_.first;
195  }
196  } else if(data.has_attribute("year")) {
197  dates_.first = dates_.second = utils::irdya_date::read_date(data["year"]);
198  }
199  set_metadata();
200 }
201 
203 {
204  return !data_.empty();
205 }
206 
208 {
209  image_label_ = data_["image"].str();
210 
211  int min = data_["min_players"].to_int(1);
212  int max = data_["max_players"].to_int(1);
213 
214  min_players_ = max_players_ = min;
215 
216  if(max > min) {
217  max_players_ = max;
218  }
219 }
220 
222 {
223  data_["completed"] = prefs::get().is_campaign_completed(data_["id"]);
224 
225  for(auto& cfg : data_.child_range("difficulty")) {
226  cfg["completed_at"] = prefs::get().is_campaign_completed(data_["id"], cfg["define"]);
227  }
228 }
229 
231  : current_level_type_()
232  , current_level_index_(0)
233  , current_era_index_(0)
234  , level_name_filter_()
235  , player_count_filter_(1)
236  , type_map_()
237  , user_map_names_()
238  , user_scenario_names_()
239  , eras_()
240  , mods_()
241  , state_(state)
242  , dependency_manager_(nullptr)
243  , generator_(nullptr)
244  , selected_campaign_difficulty_()
245  , game_config_(game_config_manager::get()->game_config())
246 {
247  // Set up the type map. Do this first!
248  type_map_.emplace(level_type::type::scenario, type_list());
249  type_map_.emplace(level_type::type::user_map, type_list());
250  type_map_.emplace(level_type::type::user_scenario, type_list());
251  type_map_.emplace(level_type::type::campaign, type_list());
252  type_map_.emplace(level_type::type::sp_campaign, type_list());
253  type_map_.emplace(level_type::type::random_map, type_list());
254 
255  DBG_MP << "restoring game config";
256 
257  // Restore game config for multiplayer.
259 
260  state_.clear();
262 
264 
265  // Initialize dependency_manager_ after refreshing game config.
267 
268  // TODO: the editor dir is already configurable, is the preferences value
271 
274 
275  DBG_MP << "initializing all levels, eras and mods";
276 
277  init_all_levels();
278  init_extras(ERA);
279  init_extras(MOD);
280 
281  state_.mp_settings().saved_game = saved_game_mode::type::no;
282 
283  for(const std::string& str : prefs::get().modifications(state_.classification().is_multiplayer())) {
284  if(game_config_.find_child("modification", "id", str)) {
285  state_.classification().active_mods.push_back(str);
286  }
287  }
288 
289  dependency_manager_->try_modifications(state_.classification().active_mods, true);
290 
292 }
293 
295 {
296  DBG_MP << "initializing generated level data";
297 
298  //DBG_MP << "current data:";
299  //DBG_MP << current_level().data().debug();
300 
301  random_map * cur_lev = dynamic_cast<random_map *> (&current_level());
302 
303  if(!cur_lev) {
304  WRN_MP << "Tried to initialized generated level data on a level that wasn't a random map";
305  return;
306  }
307 
308  try {
309  if(!cur_lev->generate_whole_scenario())
310  {
311  DBG_MP << "** replacing map **";
312 
313  config data = cur_lev->data();
314 
315  data["map_data"] = generator_->create_map();
316 
317  cur_lev->set_data(data);
318 
319  } else { //scenario generation
320 
321  DBG_MP << "** replacing scenario **";
322 
323  config data = generator_->create_scenario();
324 
325  // Set the scenario to have placing of sides
326  // based on the terrain they prefer
327  if(!data.has_attribute("modify_placing")) {
328  data["modify_placing"] = true;
329  }
330 
331  const std::string& description = cur_lev->data()["description"];
332  data["description"] = description;
334 
335  cur_lev->set_data(data);
336  }
337  } catch (const mapgen_exception & e) {
338  config data = cur_lev->data();
339 
340  data["error_message"] = e.what();
341 
342  cur_lev->set_data(data);
343  }
344 
345  //DBG_MP << "final data:";
346  //DBG_MP << current_level().data().debug();
347 }
348 
350 {
351  //
352  // We exclude campaigns from this check since they require preprocessing in order to check
353  // their side data. Since this function is used by the MP Create screen to verify side data
354  // before proceeding to Staging, this should cover most cases of false positives. It does,
355  // however, leave open the possibility of scenarios that require preprocessing before their
356  // side data is accessible, but that's an unlikely occurrence.
357  //
358  if(is_campaign()) {
359  return true;
360  }
361 
362  return current_level().data().has_child("side");
363 }
364 
366 {
367  DBG_MP << "preparing mp_game_settings for new level";
370 }
371 
373 {
374  get_parameters();
376  for(const std::string& mod_id : state_.classification().active_mods) {
377  state_.classification().mod_defines.push_back(game_config_.find_mandatory_child("modification", "id", mod_id)["define"].str());
378  }
379 }
380 
382 {
383  DBG_MP << "preparing data for scenario by reloading game config";
384 
385  state_.classification().scenario_define = current_level().data()["define"].str();
386 
388  config {"next_scenario", current_level().data()["id"]}
389  );
390 }
391 
392 void create_engine::prepare_for_campaign(const std::string& difficulty)
393 {
394  DBG_MP << "preparing data for campaign by reloading game config";
395 
396  if(!difficulty.empty()) {
397  state_.classification().difficulty = difficulty;
398  } else if(!selected_campaign_difficulty_.empty()) {
400  }
401 
402  config& current_level_data = current_level().data();
403 
404  state_.classification().campaign = current_level_data["id"].str();
405  state_.classification().campaign_name = current_level_data["name"].str();
406  state_.classification().abbrev = current_level_data["abbrev"].str();
407 
408  state_.classification().end_text = current_level_data["end_text"].str();
409  state_.classification().end_text_duration = chrono::parse_duration<std::chrono::milliseconds>(current_level_data["end_text_duration"]);
410  state_.classification().end_credits = current_level_data["end_credits"].to_bool(true);
411 
412  state_.classification().campaign_define = current_level_data["define"].str();
414  utils::split(current_level_data["extra_defines"]);
415 
417  config {"next_scenario", current_level_data["first_scenario"]}
418  );
419 }
420 
422 {
423  // Verify the existence of difficulties
424  std::vector<std::string> difficulties;
425 
426  for(const config& d : current_level().data().child_range("difficulty")) {
427  difficulties.push_back(d["define"]);
428  }
429 
430  // No difficulties found. Exit
431  if(difficulties.empty()) {
432  return "";
433  }
434 
435  // One difficulty found. Use it
436  if(difficulties.size() == 1) {
437  return difficulties[0];
438  }
439 
440  // A specific difficulty value was passed
441  // Use a minimalistic interface to get the specified define
442  if(set_value != -1) {
443  if(set_value > static_cast<int>(difficulties.size())) {
444  PLAIN_LOG << "incorrect difficulty number: [" <<
445  set_value << "]. maximum is [" << difficulties.size() << "].\n";
446  return "FAIL";
447  } else if(set_value < 1) {
448  PLAIN_LOG << "incorrect difficulty number: [" <<
449  set_value << "]. minimum is [1].\n";
450  return "FAIL";
451  } else {
452  return difficulties[set_value - 1];
453  }
454  }
455 
456  // If not, let the user pick one from the prompt
457  // We don't pass the difficulties vector here because additional data is required
458  // to constrict the dialog
460  dlg.show();
461 
463 
465 }
466 
468 {
469  DBG_MP << "preparing mp_game_settings for saved game";
470 
472 
473  // The save might be a start-of-scenario save so make sure we have the scenario data loaded.
475  state_.mp_settings().saved_game = state_.is_mid_game_save() ? saved_game_mode::type::midgame : saved_game_mode::type::scenaro_start;
476 }
477 
479 {
480  DBG_MP << "prepare_for_other";
484 }
485 
486 void create_engine::apply_level_filter(const std::string& name)
487 {
488  level_name_filter_ = name;
490 }
491 
493 {
494  player_count_filter_ = players;
496 }
497 
499 {
500  for(auto& type : type_map_) {
501  type.second.reset_filter();
502  }
503 
504  level_name_filter_ = "";
505 }
506 
508 {
510 }
511 
513 {
515 }
516 
518 {
519  try {
520  current_level_index_ = type_map_.at(current_level_type_).games_filtered.at(index);
521  } catch (const std::out_of_range&) {
523  }
524 
525  if(current_level_type_ == level_type::type::random_map) {
526  random_map* current_random_map = dynamic_cast<random_map*>(&current_level());
527 
528  // If dynamic cast has failed then we somehow have gotten all the pointers mixed together.
529  assert(current_random_map);
530 
531  generator_.reset(current_random_map->create_map_generator());
532  } else {
533  generator_.reset(nullptr);
534  }
535 
537  dependency_manager_->try_scenario(current_level().id());
538  }
539 }
540 
541 void create_engine::set_current_era_index(const std::size_t index, bool force)
542 {
544 
545  dependency_manager_->try_era_by_index(index, force);
546 }
547 
548 bool create_engine::toggle_mod(const std::string& id, bool force)
549 {
550  force |= state_.classification().type != campaign_type::type::multiplayer;
551 
552  bool is_active = dependency_manager_->is_modification_active(id);
553  dependency_manager_->try_modification_by_id(id, !is_active, force);
554 
555  state_.classification().active_mods = dependency_manager_->get_modifications();
556 
557  return !is_active;
558 }
559 
561 {
562  return generator_ != nullptr;
563 }
564 
566 {
567  return generator_->allow_user_config();
568 }
569 
571 {
572  generator_->user_config();
573 }
574 
575 std::pair<level_type::type, int> create_engine::find_level_by_id(const std::string& id) const
576 {
577  for(const auto& type : type_map_) {
578  int i = 0;
579 
580  for(const auto& game : type.second.games) {
581  if(game->id() == id) {
582  return {type.first, i};
583  }
584 
585  i++;
586  }
587  }
588 
589  return {level_type::type::sp_campaign, -1};
590 }
591 
592 int create_engine::find_extra_by_id(const MP_EXTRA extra_type, const std::string& id) const
593 {
594  int i = 0;
595  for(extras_metadata_ptr extra : get_const_extras_by_type(extra_type)) {
596  if(extra->id == id) {
597  return i;
598  }
599  i++;
600  }
601 
602  return -1;
603 }
604 
606 {
607  state_.classification().active_mods = dependency_manager_->get_modifications();
608 }
609 
610 std::vector<std::string>& create_engine::active_mods()
611 {
613 }
614 
615 std::vector<create_engine::extras_metadata_ptr> create_engine::active_mods_data()
616 {
617  const std::vector<extras_metadata_ptr>& mods = get_const_extras_by_type(MP_EXTRA::MOD);
618 
619  std::vector<extras_metadata_ptr> data_vec;
620  std::copy_if(mods.begin(), mods.end(), std::back_inserter(data_vec), [this](extras_metadata_ptr mod) {
621  return dependency_manager_->is_modification_active(mod->id);
622  });
623 
624  return data_vec;
625 }
626 
628 {
629  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
630  return *eras_[era_index]->cfg;
631 }
632 
634 {
635  DBG_MP << "getting parameter values";
636 
637  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
638  state_.classification().era_id = eras_[era_index]->id;
639  state_.mp_settings().mp_era_name = eras_[era_index]->name;
640 
641  return state_.mp_settings();
642 }
643 
645 {
646  if(auto generic_multiplayer = game_config_.optional_child("generic_multiplayer")) {
647  config gen_mp_data = *generic_multiplayer;
648 
649  // User maps.
650  int dep_index_offset = 0;
651  for(std::size_t i = 0; i < user_map_names_.size(); i++)
652  {
653  config user_map_data = gen_mp_data;
654  user_map_data["map_data"] = filesystem::read_map(user_map_names_[i]);
655 
656  // Check if a file is actually a map.
657  // Note that invalid maps should be displayed in order to
658  // show error messages in the GUI.
659  bool add_map = true;
660  std::unique_ptr<gamemap> map;
661  try {
662  map.reset(new gamemap(user_map_data["map_data"]));
663  } catch (const incorrect_map_format_error& e) {
664  // Set map content to nullptr, so that it fails can_launch_game()
665  map.reset(nullptr);
666  user_map_data["description"] = _("Map could not be loaded: ") + e.message;
667 
668  ERR_CF << "map could not be loaded: " << e.message;
669  } catch (const wml_exception&) {
670  add_map = false;
671  dep_index_offset++;
672  }
673 
674  if(add_map) {
675  type_map_[level_type::type::user_map].games.emplace_back(new user_map(user_map_data, user_map_names_[i], map.get()));
676 
677  // Since user maps are treated as scenarios, some dependency info is required
678  config depinfo;
679  depinfo["id"] = user_map_names_[i];
680  depinfo["name"] = user_map_names_[i];
681  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset);
682  }
683  }
684 
685  // User made scenarios.
686  dep_index_offset = 0;
687  for(std::size_t i = 0; i < user_scenario_names_.size(); i++)
688  {
689  config data;
690  try {
692  } catch(const config::error & e) {
693  ERR_CF << "Caught a config error while parsing user made (editor) scenarios:\n" << e.message;
694  ERR_CF << "Skipping file: " << (filesystem::get_legacy_editor_dir() + "/scenarios/" + user_scenario_names_[i]);
695  continue;
696  }
697 
698  scenario_ptr new_scenario(new scenario(data));
699  if(new_scenario->id().empty()) continue;
700 
701  type_map_[level_type::type::user_scenario].games.push_back(std::move(new_scenario));
702 
703  // Since user scenarios are treated as scenarios, some dependency info is required
704  config depinfo;
705  depinfo["id"] = data["id"];
706  depinfo["name"] = data["name"];
707  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset++);
708  }
709  }
710 
711  // Stand-alone scenarios.
712  for(const config& data : game_config_.child_range("multiplayer"))
713  {
714  if(!data["allow_new_game"].to_bool(true))
715  continue;
716 
717  if(!data["campaign_id"].empty())
718  continue;
719 
720  if(data.has_attribute("map_generation") || data.has_attribute("scenario_generation")) {
721  type_map_[level_type::type::random_map].games.emplace_back(new random_map(data));
722  } else {
723  type_map_[level_type::type::scenario].games.emplace_back(new scenario(data));
724  }
725  }
726 
727  // Campaigns.
728  for(const config& data : game_config_.child_range("campaign"))
729  {
730  if(data["id"].empty()) {
731  if(data["name"].empty()) {
732  ERR_CF << "Found a [campaign] with neither a name nor an id attribute, ignoring it";
733  } else {
734  ERR_CF << "Ignoring a [campaign] with no id attribute, but name '" << data["name"] << "'";
735  }
736  continue;
737  }
738 
739  const std::string& type = data["type"];
740  const bool mp = state_.classification().is_multiplayer();
741 
742  if(type == "mp" || (type == "hybrid" && mp)) {
743  type_map_[level_type::type::campaign].games.emplace_back(new campaign(data));
744  }
745 
746  if(type == "sp" || type.empty() || (type == "hybrid" && !mp)) {
747  campaign_ptr new_sp_campaign(new campaign(data));
748  new_sp_campaign->mark_if_completed();
749 
750  type_map_[level_type::type::sp_campaign].games.push_back(std::move(new_sp_campaign));
751  }
752  }
753 
754  auto& sp_campaigns = type_map_[level_type::type::sp_campaign].games;
755 
756  // Sort sp campaigns by rank.
757  std::stable_sort(sp_campaigns.begin(), sp_campaigns.end(),
759  return a->data()["rank"].to_int(1000) < b->data()["rank"].to_int(1000);
760  }
761  );
762 }
763 
764 void create_engine::init_extras(const MP_EXTRA extra_type)
765 {
766  std::vector<extras_metadata_ptr>& extras = get_extras_by_type(extra_type);
767  const std::string extra_name = (extra_type == ERA) ? "era" : "modification";
768 
769  component_availability::type default_availabilty = (extra_type == ERA)
770  ? component_availability::type::mp
771  : component_availability::type::hybrid;
772 
773  std::set<std::string> found_ids;
774  for(const config& extra : game_config_.child_range(extra_name))
775  {
776  component_availability::type type = component_availability::get_enum(extra["type"].str()).value_or(default_availabilty);
777  const bool mp = state_.classification().is_multiplayer();
778 
779  if((type != component_availability::type::mp || mp) && (type != component_availability::type::sp || !mp) )
780  {
781  if(found_ids.insert(extra["id"]).second) {
782  extras_metadata_ptr new_extras_metadata(new extras_metadata());
783  new_extras_metadata->id = extra["id"].str();
784  new_extras_metadata->name = extra["name"].str();
785  new_extras_metadata->description = extra["description"].str();
786  new_extras_metadata->cfg = &extra;
787 
788  extras.push_back(std::move(new_extras_metadata));
789  }
790  else {
791  ERR_CF << "found " << extra_name << " with id=" << extra["id"] << " twice";
792  }
793  }
794  }
795 }
796 
798 {
799  for(auto& type : type_map_) {
800  type.second.apply_filter(player_count_filter_, level_name_filter_);
801  }
802 }
803 
804 std::vector<create_engine::level_ptr> create_engine::get_levels_by_type_unfiltered(level_type::type type) const
805 {
806  std::vector<level_ptr> levels;
807  for(const level_ptr& lvl : type_map_.at(type).games) {
808  levels.push_back(lvl);
809  }
810 
811  return levels;
812 }
813 
814 std::vector<create_engine::level_ptr> create_engine::get_levels_by_type(level_type::type type) const
815 {
816  auto& g_list = type_map_.at(type);
817 
818  std::vector<level_ptr> levels;
819  for(std::size_t level : g_list.games_filtered) {
820  levels.push_back(g_list.games[level]);
821  }
822 
823  return levels;
824 }
825 
827 {
828  return type_map_.at(type).games_filtered;
829 }
830 
831 const std::vector<create_engine::extras_metadata_ptr>&
833 {
834  return (extra_type == ERA) ? eras_ : mods_;
835 }
836 
837 std::vector<create_engine::extras_metadata_ptr>&
839 {
840  return (extra_type == ERA) ? eras_ : mods_;
841 }
842 
844 {
845  return state_;
846 }
847 
848 } // end namespace ng
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:366
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:316
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
child_itors child_range(config_key_type key)
Definition: config.cpp:272
bool empty() const
Definition: config.cpp:849
void clear()
Definition: config.cpp:828
std::string hash() const
Definition: config.cpp:1283
config & add_child(config_key_type key)
Definition: config.cpp:440
std::vector< std::string > campaign_xtra_defines
more customization of data
std::vector< std::string > mod_defines
If there are defines the modifications use to customize data.
std::string scenario_define
If there is a define the scenario uses to customize data.
std::string difficulty
The difficulty level the game is being played on.
std::string era_define
If there is a define the era uses to customize data.
std::chrono::milliseconds end_text_duration
for how long the end-of-campaign text is shown
std::vector< std::string > active_mods
campaign_type::type type
bool end_credits
whether to show the standard credits at the end
std::string campaign_define
If there is a define the campaign uses to customize data.
std::string campaign
The id of the campaign being played.
std::string abbrev
the campaign abbreviation
std::string end_text
end-of-campaign text
std::string campaign_name
The name of the campaign being played.
static game_config_manager * get()
void load_game_config_for_game(const game_classification &classification, const std::string &scenario_id)
void load_game_config_for_create(bool is_mp, bool is_test=false)
optional_const_config optional_child(config_key_type key) const
optional_const_config find_child(config_key_type key, const std::string &name, const std::string &value) const
config_array_view child_range(config_key_type key) const
const config & find_mandatory_child(config_key_type key, const std::string &name, const std::string &value) const
Encapsulates the map of the game.
Definition: map.hpp:172
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
bool show(const unsigned auto_close_time=0)
Shows the window.
std::pair< utils::irdya_date, utils::irdya_date > dates_
campaign(const config &data)
void mark_if_completed()
std::string image_label_
bool can_launch_game() const
std::string level_name_filter_
int find_extra_by_id(const MP_EXTRA extra_type, const std::string &id) const
create_engine(saved_game &state)
std::shared_ptr< campaign > campaign_ptr
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
std::vector< level_ptr > get_levels_by_type(level_type::type type) const
std::string selected_campaign_difficulty_
bool generator_has_settings() const
std::vector< std::string > & active_mods()
std::vector< std::string > user_map_names_
bool current_level_has_side_data()
Returns true if the current level has one or more [side] tags.
bool generator_assigned() const
std::map< level_type::type, type_list > type_map_
void init_extras(const MP_EXTRA extra_type)
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)
const extras_metadata & current_era() const
std::size_t current_era_index_
const config & curent_era_cfg() const
std::vector< extras_metadata_ptr > mods_
std::unique_ptr< depcheck::manager > dependency_manager_
std::vector< std::string > user_scenario_names_
std::vector< extras_metadata_ptr > active_mods_data()
std::shared_ptr< level > level_ptr
const game_config_view & game_config_
Reference to the main game config.
std::unique_ptr< map_generator > generator_
std::pair< level_type::type, int > find_level_by_id(const std::string &id) const
saved_game & get_state()
bool is_campaign() const
Wrapper to simplify the is-type-campaign-or-sp-campaign check.
std::vector< extras_metadata_ptr > eras_
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()
std::shared_ptr< extras_metadata > extras_metadata_ptr
saved_game & state_
void set_current_level(const std::size_t index)
void prepare_for_era_and_mods()
void init_generated_level_data()
level_type::type current_level_type_
std::size_t current_level_index_
level & current_level() const
std::shared_ptr< scenario > scenario_ptr
Note to all triers: It's not guaranteed that the specified component will be selected (if the user de...
Definition: depcheck.hpp:50
Base class for all level type classes.
const config & data() const
void set_data(const config &data)
virtual bool allow_era_choice() const
level(const config &data)
bool generate_whole_scenario() const
const config & generator_data() const
random_map(const config &data)
std::string generator_name() const
map_generator * create_map_generator() const
std::unique_ptr< gamemap > map_
scenario(const config &data)
void set_metadata()
std::string map_size() const
bool can_launch_game() const
user_map(const config &data, const std::string &name, gamemap *map)
std::string description() const
static prefs & get()
bool is_campaign_completed(const std::string &campaign_id)
game_classification & classification()
Definition: saved_game.hpp:56
bool is_mid_game_save() const
Definition: saved_game.hpp:106
void expand_scenario()
copies the content of a [scenario] with the correct id attribute from the game config into this objec...
Definition: saved_game.cpp:284
void set_carryover_sides_start(config carryover_sides_start)
Definition: saved_game.cpp:164
std::string get_scenario_id() const
Definition: saved_game.cpp:679
static void post_scenario_generation(const config &old_scenario, config &generated_scenario)
copies attributes & tags from the 'outer' [scenario] to the scenario that is generated by scenario_ge...
Definition: saved_game.cpp:539
void clear()
Definition: saved_game.cpp:814
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:60
void set_scenario(config scenario)
Definition: saved_game.cpp:596
void check_require_scenario()
Add addon_id information if needed.
Definition: saved_game.cpp:312
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:505
static irdya_date read_date(const std::string &date)
static lg::log_domain log_mp_create_engine("mp/create/engine")
#define WRN_MP
#define DBG_MP
#define ERR_CF
static lg::log_domain log_config("config")
Declarations for File-IO.
std::size_t i
Definition: function.cpp:1028
static std::string _(const char *str)
Definition: gettext.hpp:93
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:299
map_generator * create_map_generator(const std::string &name, const config &cfg, const config *vars)
Definition: map_create.cpp:28
CURSOR_TYPE get()
Definition: cursor.cpp:216
std::string get_legacy_editor_dir()
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:444
std::string read_map(const std::string &name)
const std::string unicode_multiplication_sign
Definition: constants.cpp:46
Game configuration data as global variables.
Definition: build_info.cpp:61
static bool is_active(const widget *wgt)
Definition: window.cpp:1267
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:50
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.
Definition: unicode.cpp:70
std::vector< std::string > split(const config_attribute_value &val)
std::string_view data
Definition: picture.cpp:178
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:622
std::string mp_era_name
saved_game_mode::type saved_game
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition: enum_base.hpp:57
Helper class, don't construct this directly.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define d
#define e
#define b