The Battle for Wesnoth  1.15.11+dev
create_engine.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2018 by Andrius Silinskas <silinskas.andrius@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "filesystem.hpp"
18 #include "game_config_manager.hpp"
20 #include "preferences/game.hpp"
23 #include "log.hpp"
24 #include "map/exception.hpp"
25 #include "map/map.hpp"
26 #include "minimap.hpp"
27 #include "saved_game.hpp"
28 #include "wml_exception.hpp"
29 
31 #include "serialization/parser.hpp"
33 
34 #include <sstream>
35 #include <cctype>
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 
46 level::level(const config& data)
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  data_["description"] = _("Map could not be loaded: ") + e.message;
73 
74  ERR_CF << "map could not be loaded: " << e.message << '\n';
75  } catch(const wml_exception& e) {
76  data_["description"] = _("Map could not be loaded.");
77 
78  ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
79  }
80 
81  set_sides();
82 }
83 
84 std::string scenario::map_size() const
85 {
86  std::stringstream map_size;
87 
88  if(map_.get() != nullptr) {
89  map_size << map_->w();
91  map_size << map_->h();
92  } else {
93  map_size << _("not available.");
94  }
95 
96  return map_size.str();
97 }
98 
100 {
101  if(map_.get() != nullptr) {
102  // If there are fewer sides in the configuration than there are
103  // starting positions, then generate the additional sides
104  const int map_positions = map_->num_valid_starting_positions();
105 
106  if(!data_.has_child("side")) {
107  for(int pos = 0; pos < map_positions; ++pos) {
108  config& side = data_.add_child("side");
109  side["side"] = pos + 1;
110  side["team_name"] = "Team " + std::to_string(pos + 1);
111  side["canrecruit"] = true;
112  side["controller"] = "human";
113  }
114  }
115 
116  num_players_ = 0;
117  for(const config& scenario : data_.child_range("side")) {
118  if(scenario["allow_player"].to_bool(true)) {
119  ++num_players_;
120  }
121  }
122  }
123 }
124 
125 user_map::user_map(const config& data, const std::string& name, gamemap* map)
126  : scenario(data)
127  , name_(name)
128 {
129  if(map != nullptr) {
130  map_.reset(new gamemap(*map));
131  }
132 
133  set_metadata();
134 }
135 
137 {
138  set_sides();
139 }
140 
141 std::string user_map::description() const
142 {
143  if(!data_["description"].empty()) {
144  return data_["description"];
145  }
146 
147  // map error message
148  return _("Custom map.");
149 }
150 
152  : scenario(data)
153  , generator_data_()
154  , generate_whole_scenario_(data_.has_attribute("scenario_generation"))
155  , generator_name_(generate_whole_scenario_ ? data_["scenario_generation"] : data_["map_generation"])
156 {
157  if(!data.has_child("generator")) {
158  data_.clear();
160  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
161  data_["error_message"] = "missing [generator] tag";
162  } else {
163  generator_data_ = data.child("generator");
164  }
165 
166  if(!data.has_attribute("scenario_generation") && !data.has_attribute("map_generation")) {
167  data_.clear();
169  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
170  data_["error_message"] = "couldn't find 'scenario_generation' or 'map_generation' attribute";
171  }
172 }
173 
175 {
177 }
178 
180  : level(data)
181  , id_(data["id"])
182  , allow_era_choice_(level::allow_era_choice())
183  , image_label_()
184  , min_players_(1)
185  , max_players_(1)
186 {
187  if(data.has_attribute("start_year")) {
188  dates_.first = irdya_date::read_date(data["start_year"]);
189  if(data.has_attribute("end_year")) {
190  dates_.second = irdya_date::read_date(data["end_year"]);
191  } else {
192  dates_.second = dates_.first;
193  }
194  } else if(data.has_attribute("year")) {
195  dates_.first = dates_.second = irdya_date::read_date(data["year"]);
196  }
197  set_metadata();
198 }
199 
201 {
202  return !data_.empty();
203 }
204 
206 {
207  image_label_ = data_["image"].str();
208 
209  int min = data_["min_players"].to_int(1);
210  int max = data_["max_players"].to_int(1);
211 
212  min_players_ = max_players_ = min;
213 
214  if(max > min) {
215  max_players_ = max;
216  }
217 }
218 
220 {
221  data_["completed"] = preferences::is_campaign_completed(data_["id"]);
222 
223  for(auto& cfg : data_.child_range("difficulty")) {
224  cfg["completed_at"] = preferences::is_campaign_completed(data_["id"], cfg["define"]);
225  }
226 }
227 
229  : current_level_type_()
230  , current_level_index_(0)
231  , current_era_index_(0)
232  , level_name_filter_()
233  , player_count_filter_(1)
234  , type_map_()
235  , user_map_names_()
236  , user_scenario_names_()
237  , eras_()
238  , mods_()
239  , state_(state)
240  , dependency_manager_(nullptr)
241  , generator_(nullptr)
242  , selected_campaign_difficulty_()
243  , game_config_(game_config_manager::get()->game_config())
244 {
245  // Set up the type map. Do this first!
247  type_map_.emplace(level::TYPE::USER_MAP, type_list());
248  type_map_.emplace(level::TYPE::USER_SCENARIO, type_list());
249  type_map_.emplace(level::TYPE::CAMPAIGN, type_list());
250  type_map_.emplace(level::TYPE::SP_CAMPAIGN, type_list());
251  type_map_.emplace(level::TYPE::RANDOM_MAP, type_list());
252 
253  DBG_MP << "restoring game config\n";
254 
255  // Restore game config for multiplayer.
256  game_classification::CAMPAIGN_TYPE type = state_.classification().campaign_type;
257 
258  state_.clear();
259  state_.classification().campaign_type = type;
260 
262 
263  // Initialize dependency_manager_ after refreshing game config.
265 
266  // TODO: the editor dir is already configurable, is the preferences value
269 
272 
273  DBG_MP << "initializing all levels, eras and mods\n";
274 
275  init_all_levels();
276  init_extras(ERA);
277  init_extras(MOD);
278 
280 
281  for(const std::string& str : preferences::modifications(state_.classification().is_multiplayer())) {
282  if(game_config_.find_child("modification", "id", str)) {
283  state_.classification().active_mods.push_back(str);
284  }
285  }
286 
287  dependency_manager_->try_modifications(state_.classification().active_mods, true);
288 
290 }
291 
293 {
294  DBG_MP << "initializing generated level data\n";
295 
296  //DBG_MP << "current data:\n";
297  //DBG_MP << current_level().data().debug();
298 
299  random_map * cur_lev = dynamic_cast<random_map *> (&current_level());
300 
301  if(!cur_lev) {
302  WRN_MP << "Tried to initialized generated level data on a level that wasn't a random map\n";
303  return;
304  }
305 
306  try {
307  if(!cur_lev->generate_whole_scenario())
308  {
309  DBG_MP << "** replacing map ** \n";
310 
311  config data = cur_lev->data();
312 
313  data["map_data"] = generator_->create_map();
314 
315  cur_lev->set_data(data);
316 
317  } else { //scenario generation
318 
319  DBG_MP << "** replacing scenario ** \n";
320 
321  config data = generator_->create_scenario();
322 
323  // Set the scenario to have placing of sides
324  // based on the terrain they prefer
325  if(!data.has_attribute("modify_placing")) {
326  data["modify_placing"] = true;
327  }
328 
329  const std::string& description = cur_lev->data()["description"];
330  data["description"] = description;
331  saved_game::post_scenario_generation(cur_lev->data(), data);
332 
333  cur_lev->set_data(data);
334  }
335  } catch (const mapgen_exception & e) {
336  config data = cur_lev->data();
337 
338  data["error_message"] = e.what();
339 
340  cur_lev->set_data(data);
341  }
342 
343  //DBG_MP << "final data:\n";
344  //DBG_MP << current_level().data().debug();
345 }
346 
348 {
349  //
350  // We exclude campaigns from this check since they require preprocessing in order to check
351  // their side data. Since this function is used by the MP Create screen to verify side data
352  // before proceeding to Staging, this should cover most cases of false positives. It does,
353  // however, leave open the possibility of scenarios that require preprocessing before their
354  // side data is accessible, but that's an unlikely occurrence.
355  //
356  if(is_campaign()) {
357  return true;
358  }
359 
360  return current_level().data().has_child("side");
361 }
362 
364 {
365  DBG_MP << "preparing mp_game_settings for new level\n";
368 }
369 
371 {
372  get_parameters();
374  for(const std::string& mod_id : state_.classification().active_mods) {
375  state_.classification().mod_defines.push_back(game_config_.find_child("modification", "id", mod_id)["define"].str());
376  }
377 }
378 
380 {
381  DBG_MP << "preparing data for scenario by reloading game config\n";
382 
383  state_.classification().scenario_define = current_level().data()["define"].str();
384 
386  config {"next_scenario", current_level().data()["id"]}
387  );
388 }
389 
390 void create_engine::prepare_for_campaign(const std::string& difficulty)
391 {
392  DBG_MP << "preparing data for campaign by reloading game config\n";
393 
394  if(!difficulty.empty()) {
395  state_.classification().difficulty = difficulty;
396  } else if(!selected_campaign_difficulty_.empty()) {
398  }
399 
400  config& current_level_data = current_level().data();
401 
402  state_.classification().campaign = current_level_data["id"].str();
403  state_.classification().campaign_name = current_level_data["name"].str();
404  state_.classification().abbrev = current_level_data["abbrev"].str();
405 
406  state_.classification().end_text = current_level_data["end_text"].str();
407  state_.classification().end_text_duration = current_level_data["end_text_duration"];
408  state_.classification().end_credits = current_level_data["end_credits"].to_bool(true);
409 
410  state_.classification().campaign_define = current_level_data["define"].str();
412  utils::split(current_level_data["extra_defines"]);
413 
415  config {"next_scenario", current_level_data["first_scenario"]}
416  );
417 }
418 
420 {
421  // Verify the existence of difficulties
422  std::vector<std::string> difficulties;
423 
424  for(const config& d : current_level().data().child_range("difficulty")) {
425  difficulties.push_back(d["define"]);
426  }
427 
428  // No difficulties found. Exit
429  if(difficulties.empty()) {
430  return "";
431  }
432 
433  // One difficulty found. Use it
434  if(difficulties.size() == 1) {
435  return difficulties[0];
436  }
437 
438  // A specific difficulty value was passed
439  // Use a minimalistic interface to get the specified define
440  if(set_value != -1) {
441  if(set_value > static_cast<int>(difficulties.size())) {
442  std::cerr << "incorrect difficulty number: [" <<
443  set_value << "]. maximum is [" << difficulties.size() << "].\n";
444  return "FAIL";
445  } else if(set_value < 1) {
446  std::cerr << "incorrect difficulty number: [" <<
447  set_value << "]. minimum is [1].\n";
448  return "FAIL";
449  } else {
450  return difficulties[set_value - 1];
451  }
452  }
453 
454  // If not, let the user pick one from the prompt
455  // We don't pass the difficulties vector here because additional data is required
456  // to constrict the dialog
458  dlg.show();
459 
461 
463 }
464 
466 {
467  DBG_MP << "preparing mp_game_settings for saved game\n";
468 
470 
471  // The save might be a start-of-scenario save so make sure we have the scenario data loaded.
473  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;
474 }
475 
477 {
478  DBG_MP << "prepare_for_other\n";
482 }
483 
484 void create_engine::apply_level_filter(const std::string& name)
485 {
486  level_name_filter_ = name;
488 }
489 
491 {
492  player_count_filter_ = players;
494 }
495 
497 {
498  for(auto& type : type_map_) {
499  type.second.reset_filter();
500  }
501 
502  level_name_filter_ = "";
503 }
504 
506 {
508 }
509 
511 {
513 }
514 
516 {
517  try {
518  current_level_index_ = type_map_.at(current_level_type_.v).games_filtered.at(index);
519  } catch (const std::out_of_range&) {
521  }
522 
523  if(current_level_type_ == level::TYPE::RANDOM_MAP) {
524  random_map* current_random_map = dynamic_cast<random_map*>(&current_level());
525 
526  // If dynamic cast has failed then we somehow have gotten all the pointers mixed together.
527  assert(current_random_map);
528 
529  generator_.reset(current_random_map->create_map_generator());
530  } else {
531  generator_.reset(nullptr);
532  }
533 
535  dependency_manager_->try_scenario(current_level().id());
536  }
537 }
538 
539 void create_engine::set_current_era_index(const std::size_t index, bool force)
540 {
542 
543  dependency_manager_->try_era_by_index(index, force);
544 }
545 
546 bool create_engine::toggle_mod(int index, bool force)
547 {
548  force |= state_.classification().campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
549 
550  bool is_active = dependency_manager_->is_modification_active(index);
551  dependency_manager_->try_modification_by_index(index, !is_active, force);
552 
553  state_.classification().active_mods = dependency_manager_->get_modifications();
554 
555  return !is_active;
556 }
557 
559 {
560  return generator_ != nullptr;
561 }
562 
564 {
565  return generator_->allow_user_config();
566 }
567 
569 {
570  generator_->user_config();
571 }
572 
573 std::pair<level::TYPE, int> create_engine::find_level_by_id(const std::string& id) const
574 {
575  for(const auto& type : type_map_) {
576  int i = 0;
577 
578  for(const auto& game : type.second.games) {
579  if(game->id() == id) {
580  return {type.first, i};
581  }
582 
583  i++;
584  }
585  }
586 
587  return {level::TYPE::SP_CAMPAIGN, -1};
588 }
589 
590 int create_engine::find_extra_by_id(const MP_EXTRA extra_type, const std::string& id) const
591 {
592  int i = 0;
593  for(extras_metadata_ptr extra : get_const_extras_by_type(extra_type)) {
594  if(extra->id == id) {
595  return i;
596  }
597  i++;
598  }
599 
600  return -1;
601 }
602 
604 {
605  state_.classification().active_mods = dependency_manager_->get_modifications();
606 }
607 
608 std::vector<std::string>& create_engine::active_mods()
609 {
611 }
612 
613 std::vector<create_engine::extras_metadata_ptr> create_engine::active_mods_data()
614 {
615  const std::vector<extras_metadata_ptr>& mods = get_const_extras_by_type(MP_EXTRA::MOD);
616 
617  std::vector<extras_metadata_ptr> data_vec;
618  std::copy_if(mods.begin(), mods.end(), std::back_inserter(data_vec), [this](extras_metadata_ptr mod) {
619  return dependency_manager_->is_modification_active(mod->id);
620  });
621 
622  return data_vec;
623 }
624 
626 {
627  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
628  return *eras_[era_index]->cfg;
629 }
630 
632 {
633  DBG_MP << "getting parameter values" << std::endl;
634 
635  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
636  state_.classification().era_id = eras_[era_index]->id;
637  state_.mp_settings().mp_era_name = eras_[era_index]->name;
638 
639  return state_.mp_settings();
640 }
641 
643 {
644  if(const config& generic_multiplayer = game_config_.child("generic_multiplayer")) {
645  config gen_mp_data = generic_multiplayer;
646 
647  // User maps.
648  int dep_index_offset = 0;
649  for(std::size_t i = 0; i < user_map_names_.size(); i++)
650  {
651  config user_map_data = gen_mp_data;
652  user_map_data["map_data"] = filesystem::read_map(user_map_names_[i]);
653 
654  // Check if a file is actually a map.
655  // Note that invalid maps should be displayed in order to
656  // show error messages in the GUI.
657  bool add_map = true;
658  std::unique_ptr<gamemap> map;
659  try {
660  map.reset(new gamemap(user_map_data["map_data"]));
661  } catch (const incorrect_map_format_error& e) {
662  user_map_data["description"] = _("Map could not be loaded: ") + e.message;
663 
664  ERR_CF << "map could not be loaded: " << e.message << '\n';
665  } catch (const wml_exception&) {
666  add_map = false;
667  dep_index_offset++;
668  }
669 
670  if(add_map) {
671  type_map_[level::TYPE::USER_MAP].games.emplace_back(new user_map(user_map_data, user_map_names_[i], map.get()));
672 
673  // Since user maps are treated as scenarios, some dependency info is required
674  config depinfo;
675  depinfo["id"] = user_map_names_[i];
676  depinfo["name"] = user_map_names_[i];
677  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset);
678  }
679  }
680 
681  // User made scenarios.
682  dep_index_offset = 0;
683  for(std::size_t i = 0; i < user_scenario_names_.size(); i++)
684  {
685  config data;
686  try {
687  read(data, *preprocess_file(filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i]));
688  } catch(const config::error & e) {
689  ERR_CF << "Caught a config error while parsing user made (editor) scenarios:\n" << e.message << std::endl;
690  ERR_CF << "Skipping file: " << (filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i]) << std::endl;
691  continue;
692  }
693 
694  scenario_ptr new_scenario(new scenario(data));
695  if(new_scenario->id().empty()) continue;
696 
697  type_map_[level::TYPE::USER_SCENARIO].games.push_back(std::move(new_scenario));
698 
699  // Since user scenarios are treated as scenarios, some dependency info is required
700  config depinfo;
701  depinfo["id"] = data["id"];
702  depinfo["name"] = data["name"];
703  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset++);
704  }
705  }
706 
707  // Stand-alone scenarios.
708  for(const config& data : game_config_.child_range("multiplayer"))
709  {
710  if(!data["allow_new_game"].to_bool(true))
711  continue;
712 
713  if(!data["campaign_id"].empty())
714  continue;
715 
716  if(data.has_attribute("map_generation") || data.has_attribute("scenario_generation")) {
717  type_map_[level::TYPE::RANDOM_MAP].games.emplace_back(new random_map(data));
718  } else {
719  type_map_[level::TYPE::SCENARIO].games.emplace_back(new scenario(data));
720  }
721  }
722 
723  // Campaigns.
724  for(const config& data : game_config_.child_range("campaign"))
725  {
726  if(data["id"].empty()) {
727  if(data["name"].empty()) {
728  ERR_CF << "Found a [campaign] with neither a name nor an id attribute, ignoring it" << std::endl;
729  } else {
730  ERR_CF << "Ignoring a [campaign] with no id attribute, but name '" << data["name"] << "'" << std::endl;
731  }
732  continue;
733  }
734 
735  const std::string& type = data["type"];
736  const bool mp = state_.classification().is_multiplayer();
737 
738  if(type == "mp" || (type == "hybrid" && mp)) {
739  type_map_[level::TYPE::CAMPAIGN].games.emplace_back(new campaign(data));
740  }
741 
742  if(type == "sp" || type.empty() || (type == "hybrid" && !mp)) {
743  campaign_ptr new_sp_campaign(new campaign(data));
744  new_sp_campaign->mark_if_completed();
745 
746  type_map_[level::TYPE::SP_CAMPAIGN].games.push_back(std::move(new_sp_campaign));
747  }
748  }
749 
750  auto& sp_campaigns = type_map_[level::TYPE::SP_CAMPAIGN].games;
751 
752  // Sort sp campaigns by rank.
753  std::stable_sort(sp_campaigns.begin(), sp_campaigns.end(),
755  return a->data()["rank"].to_int(1000) < b->data()["rank"].to_int(1000);
756  }
757  );
758 }
759 
760 void create_engine::init_extras(const MP_EXTRA extra_type)
761 {
762  std::vector<extras_metadata_ptr>& extras = get_extras_by_type(extra_type);
763  const std::string extra_name = (extra_type == ERA) ? "era" : "modification";
764 
765  ng::depcheck::component_availability default_availabilty = (extra_type == ERA)
766  ? ng::depcheck::component_availability::MP
767  : ng::depcheck::component_availability::HYBRID;
768 
769  std::set<std::string> found_ids;
770  for(const config& extra : game_config_.child_range(extra_name))
771  {
772  ng::depcheck::component_availability type = extra["type"].to_enum(default_availabilty);
773  const bool mp = state_.classification().is_multiplayer();
774 
775  if((type != ng::depcheck::component_availability::MP || mp) && (type != ng::depcheck::component_availability::SP || !mp) )
776  {
777  if(found_ids.insert(extra["id"]).second) {
778  extras_metadata_ptr new_extras_metadata(new extras_metadata());
779  new_extras_metadata->id = extra["id"].str();
780  new_extras_metadata->name = extra["name"].str();
781  new_extras_metadata->description = extra["description"].str();
782  new_extras_metadata->cfg = &extra;
783 
784  extras.push_back(std::move(new_extras_metadata));
785  }
786  else {
787  //TODO: use a more visible error message.
788  ERR_CF << "found " << extra_name << " with id=" << extra["id"] << " twice\n";
789  }
790  }
791  }
792 }
793 
795 {
796  for(auto& type : type_map_) {
797  type.second.apply_filter(player_count_filter_, level_name_filter_);
798  }
799 }
800 
801 std::vector<create_engine::level_ptr> create_engine::get_levels_by_type_unfiltered(level::TYPE type) const
802 {
803  std::vector<level_ptr> levels;
804  for(const level_ptr& lvl : type_map_.at(type.v).games) {
805  levels.push_back(lvl);
806  }
807 
808  return levels;
809 }
810 
811 std::vector<create_engine::level_ptr> create_engine::get_levels_by_type(level::TYPE type) const
812 {
813  auto& g_list = type_map_.at(type.v);
814 
815  std::vector<level_ptr> levels;
816  for(std::size_t level : g_list.games_filtered) {
817  levels.push_back(g_list.games[level]);
818  }
819 
820  return levels;
821 }
822 
824 {
825  return type_map_.at(type.v).games_filtered;
826 }
827 
828 const std::vector<create_engine::extras_metadata_ptr>&
830 {
831  return (extra_type == ERA) ? eras_ : mods_;
832 }
833 
834 std::vector<create_engine::extras_metadata_ptr>&
836 {
837  return (extra_type == ERA) ? eras_ : mods_;
838 }
839 
841 {
842  return state_;
843 }
844 
845 } // end namespace ng
TYPE
Used to specify the rendering format of images.
Definition: picture.hpp:228
std::string map_size() const
void check_require_scenario()
Add addon_id information if needed.
Definition: saved_game.cpp:295
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:414
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:104
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:267
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:565
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:207
#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:406
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:301
std::vector< std::string > user_scenario_names_
const config & generator_data() const
child_itors child_range(config_key_type key)
Definition: config.cpp:356
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:475
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:791
#define WRN_MP
void set_data(const config &data)
void clear()
Definition: config.cpp:895
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:509
#define d
static lg::log_domain log_config("config")
static std::string _(const char *str)
Definition: gettext.hpp:92
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:135
campaign(const config &data)
std::string get_scenario_id() const
Definition: saved_game.cpp:647
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:1333
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:51
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:626
std::string get_user_data_dir()
Definition: filesystem.cpp:789
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)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
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:45
Encapsulates the map of the game.
Definition: map.hpp:170
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:35
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:54
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::size_t current_level_index_
map_generator * create_map_generator(const std::string &name, const config &cfg, const config *vars)
Definition: map_create.cpp:28
std::size_t i
Definition: function.cpp:940
std::vector< std::string > campaign_xtra_defines
more customization of data
Default, unset return value.
Definition: retval.hpp:31
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:58
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:215
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:71
The campaign mode difficulty menu.
config & add_child(config_key_type key)
Definition: config.cpp:500
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:719
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:54
map_generator * create_map_generator() const
void set_carryover_sides_start(config carryover_sides_start)
Definition: saved_game.cpp:160
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:29
#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:59
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:58
std::string hash() const
Definition: config.cpp:1367
user_map(const config &data, const std::string &name, gamemap *map)
bool empty() const
Definition: config.cpp:916
const config & child(config_key_type key) const
virtual bool allow_era_choice() const
void init_extras(const MP_EXTRA extra_type)