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