The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
create_engine.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2017 by Andrius Silinskas <silinskas.andrius@gmail.com>
3  Part of the Battle for Wesnoth Project http://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 "formula/string_utils.hpp"
19 #include "game_config_manager.hpp"
21 #include "preferences/game.hpp"
24 #include "hash.hpp"
25 #include "image.hpp"
26 #include "log.hpp"
27 #include "map/exception.hpp"
28 #include "map/map.hpp"
29 #include "minimap.hpp"
30 #include "saved_game.hpp"
31 #include "wml_exception.hpp"
32 
34 #include "serialization/parser.hpp"
35 
36 #include <sstream>
37 #include <cctype>
38 
39 static lg::log_domain log_config("config");
40 #define ERR_CF LOG_STREAM(err, log_config)
41 
42 static lg::log_domain log_mp_create_engine("mp/create/engine");
43 #define WRN_MP LOG_STREAM(warn, log_mp_create_engine)
44 #define DBG_MP LOG_STREAM(debug, log_mp_create_engine)
45 
46 namespace ng {
47 
48 level::level(const config& data)
49  : data_(data)
50 {
51 }
52 
54  : level(data)
55  , map_()
56  , map_hash_()
57  , num_players_(0)
58 {
59  set_metadata();
60 }
61 
63 {
64  return map_.get() != nullptr;
65 }
66 
68 {
69  const std::string& map_data = data_["map_data"];
70 
71  try {
72  map_.reset(new gamemap(game_config_manager::get()->terrain_types(),
73  map_data));
74  } catch(incorrect_map_format_error& e) {
75  data_["description"] = _("Map could not be loaded: ") + e.message;
76 
77  ERR_CF << "map could not be loaded: " << e.message << '\n';
78  } catch(wml_exception& e) {
79  data_["description"] = _("Map could not be loaded.");
80 
81  ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
82  }
83 
84  set_sides();
85 }
86 
88 {
89  std::stringstream map_size;
90 
91  if(map_.get() != nullptr) {
92  map_size << map_->w();
94  map_size << map_->h();
95  } else {
96  map_size << _("not available.");
97  }
98 
99  return map_size.str();
100 }
101 
103 {
104  if(map_.get() != nullptr) {
105  // If there are fewer sides in the configuration than there are
106  // starting positions, then generate the additional sides
107  const int map_positions = map_->num_valid_starting_positions();
108 
109  for(int pos = data_.child_count("side"); 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"] = "human";
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 
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 
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_(2)
186  , max_players_(2)
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(2);
211  int max = data_["max_players"].to_int(2);
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  , current_mod_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  , video_(v)
243  , dependency_manager_(nullptr)
244  , generator_(nullptr)
245  , selected_campaign_difficulty_()
246 {
247  // Set up the type map. Do this first!
249  type_map_.emplace(level::TYPE::USER_MAP, type_list());
250  type_map_.emplace(level::TYPE::USER_SCENARIO, type_list());
251  type_map_.emplace(level::TYPE::CAMPAIGN, type_list());
252  type_map_.emplace(level::TYPE::SP_CAMPAIGN, type_list());
253  type_map_.emplace(level::TYPE::RANDOM_MAP, type_list());
254 
255  DBG_MP << "restoring game config\n";
256 
257  // Restore game config for multiplayer.
258  game_classification::CAMPAIGN_TYPE type = state_.classification().campaign_type;
259 
260  bool connect = state_.mp_settings().show_connect;
261 
262  state_.clear();
263  state_.classification().campaign_type = type;
264  state_.mp_settings().show_connect = connect;
265 
266  game_config_manager::get()->load_game_config_for_create(type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER);
267 
268  // Initialize dependency_manager_ after refreshing game config.
269  dependency_manager_.reset(new depcheck::manager(
270  game_config_manager::get()->game_config(), type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER, video_));
271 
272  // TODO: the editor dir is already configurable, is the preferences value
274  nullptr, filesystem::FILE_NAME_ONLY);
275 
277  nullptr, filesystem::FILE_NAME_ONLY);
278 
279  DBG_MP << "initializing all levels, eras and mods\n";
280 
281  init_all_levels();
282  init_extras(ERA);
283  init_extras(MOD);
284 
285  state_.mp_settings().saved_game = false;
286 
287  for(const std::string& str : preferences::modifications(state_.classification().campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER)) {
288  if(game_config_manager::get()->game_config().find_child("modification", "id", str)) {
289  state_.mp_settings().active_mods.push_back(str);
290  }
291  }
292 
293  if(current_level_type_ != level::TYPE::CAMPAIGN &&
294  current_level_type_ != level::TYPE::SP_CAMPAIGN) {
295  dependency_manager_->try_modifications(state_.mp_settings().active_mods, true);
296  }
297 
299 }
300 
302 {
303  DBG_MP << "initializing generated level data\n";
304 
305  //DBG_MP << "current data:\n";
306  //DBG_MP << current_level().data().debug();
307 
308  random_map * cur_lev = dynamic_cast<random_map *> (&current_level());
309 
310  if(!cur_lev) {
311  WRN_MP << "Tried to initialized generated level data on a level that wasn't a random map\n";
312  return;
313  }
314 
315  try {
316  if(!cur_lev->generate_whole_scenario())
317  {
318  DBG_MP << "** replacing map ** \n";
319 
320  config data = cur_lev->data();
321 
322  data["map_data"] = generator_->create_map();
323 
324  cur_lev->set_data(data);
325 
326  } else { //scenario generation
327 
328  DBG_MP << "** replacing scenario ** \n";
329 
330  config data = generator_->create_scenario();
331 
332  // Set the scenario to have placing of sides
333  // based on the terrain they prefer
334  if(!data.has_attribute("modify_placing")) {
335  data["modify_placing"] = true;
336  }
337 
338  const std::string& description = cur_lev->data()["description"];
339  data["description"] = description;
340 
341  cur_lev->set_data(data);
342  }
343  } catch (mapgen_exception & e) {
344  config data = cur_lev->data();
345 
346  data["error_message"] = e.what();
347 
348  cur_lev->set_data(data);
349  }
350 
351  //DBG_MP << "final data:\n";
352  //DBG_MP << current_level().data().debug();
353 }
354 
356 {
357  return current_level().data().has_child("side");
358 }
359 
361 {
362  DBG_MP << "preparing mp_game_settings for new level\n";
365 }
366 
368 {
369  const config& game_manager_config = game_config_manager::get()->game_config();
370 
371  state_.classification().era_define = game_manager_config.find_child("era", "id", get_parameters().mp_era)["define"].str();
372  for(const std::string& mod_id : get_parameters().active_mods) {
373  state_.classification().mod_defines.push_back(game_manager_config.find_child("modification", "id", mod_id)["define"].str());
374  }
375 }
376 
378 {
379  DBG_MP << "preparing data for scenario by reloading game config\n";
380 
381  state_.classification().scenario_define = current_level().data()["define"].str();
382 
384  config {"next_scenario", current_level().data()["id"]}
385  );
386 }
387 
389 {
390  DBG_MP << "preparing data for campaign by reloading game config\n";
391 
392  if(!difficulty.empty()) {
393  state_.classification().difficulty = difficulty;
394  } else if(!selected_campaign_difficulty_.empty()) {
396  }
397 
398  config& current_level_data = current_level().data();
399 
400  state_.classification().campaign = current_level_data["id"].str();
401  state_.classification().abbrev = current_level_data["abbrev"].str();
402 
403  state_.classification().end_text = current_level_data["end_text"].str();
404  state_.classification().end_text_duration = current_level_data["end_text_duration"];
405 
406  state_.classification().campaign_define = current_level_data["define"].str();
408  utils::split(current_level_data["extra_defines"]);
409 
411  config {"next_scenario", current_level_data["first_scenario"]}
412  );
413 }
414 
416 {
417  // Verify the existence of difficulties
418  std::vector<std::string> difficulties;
419 
420  for(const config& d : current_level().data().child_range("difficulty")) {
421  difficulties.push_back(d["define"]);
422  }
423 
424  if(difficulties.empty()) {
425  difficulties = utils::split(current_level().data()["difficulties"]);
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(video_);
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 = true;
474  state_.mp_settings().name = vgettext("$login|’s game", {{"login", preferences::login()}});
475 }
476 
478 {
479  DBG_MP << "prepare_for_other\n";
482 }
483 
485 {
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 {
512  const size_t index = (extra_type == ERA) ?
514 
515  return *get_const_extras_by_type(extra_type)[index];
516 }
517 
519 {
520  try {
521  current_level_index_ = type_map_.at(current_level_type_.v).games_filtered.at(index);
522  } catch (std::out_of_range&) {
524  }
525 
526  if(current_level_type_ == level::TYPE::RANDOM_MAP) {
527  random_map* current_random_map = dynamic_cast<random_map*>(&current_level());
528 
529  // If dynamic cast has failed then we somehow have gotten all the pointers mixed together.
530  assert(current_random_map);
531 
532  generator_.reset(current_random_map->create_map_generator());
533  } else {
534  generator_.reset(nullptr);
535  }
536 
537  if(current_level_type_ != level::TYPE::CAMPAIGN &&
538  current_level_type_ != level::TYPE::SP_CAMPAIGN) {
539 
540  dependency_manager_->try_scenario(current_level().id());
541  }
542 }
543 
544 void create_engine::set_current_era_index(const size_t index, bool force)
545 {
547 
548  dependency_manager_->try_era_by_index(index, force);
549 }
550 
552 {
553  force |= (current_level_type_ == ng::level::TYPE::CAMPAIGN || current_level_type_ == ng::level::TYPE::SP_CAMPAIGN);
554  bool is_active = dependency_manager_->is_modification_active(current_mod_index_);
555  dependency_manager_->try_modification_by_index(current_mod_index_, !is_active, force);
556 
557  state_.mp_settings().active_mods = dependency_manager_->get_modifications();
558 
559  return !is_active;
560 }
561 
563 {
564  return generator_ != nullptr;
565 }
566 
568 {
569  return generator_->allow_user_config();
570 }
571 
573 {
574  generator_->user_config();
575 }
576 
578 {
579  int i = 0;
580 
581  for(const auto& type : type_map_) {
582  i = 0;
583 
584  for(const auto game : type.second.games) {
585  if(game->id() == id) {
586  return i;
587  }
588 
589  i++;
590  }
591  }
592 
593  return -1;
594 }
595 
596 int create_engine::find_extra_by_id(const MP_EXTRA extra_type, const std::string& id) const
597 {
598  int i = 0;
599  for(extras_metadata_ptr extra : get_const_extras_by_type(extra_type)) {
600  if(extra->id == id) {
601  return i;
602  }
603  i++;
604  }
605 
606  return -1;
607 }
608 
610 {
611  for(const auto& type : type_map_) {
612  for(const auto game : type.second.games) {
613  if(game->id() == id) {
614  return type.first;
615  }
616  }
617  }
618 
619  return level::TYPE::SP_CAMPAIGN;
620 }
621 
623 {
624  state_.mp_settings().active_mods = dependency_manager_->get_modifications();
625 }
626 
627 std::vector<std::string>& create_engine::active_mods()
628 {
629  return state_.mp_settings().active_mods;
630 }
631 
632 std::vector<create_engine::extras_metadata_ptr> create_engine::active_mods_data()
633 {
634  const std::vector<extras_metadata_ptr>& mods = get_const_extras_by_type(MP_EXTRA::MOD);
635 
636  std::vector<extras_metadata_ptr> data_vec;
637  std::copy_if(mods.begin(), mods.end(), std::back_inserter(data_vec), [this](extras_metadata_ptr mod) {
638  return dependency_manager_->is_modification_active(mod->id);
639  });
640 
641  return data_vec;
642 }
643 
645 {
646  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
647  return *eras_[era_index]->cfg;
648 }
649 
651 {
652  DBG_MP << "getting parameter values" << std::endl;
653 
654  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
655  state_.mp_settings().mp_era = eras_[era_index]->id;
656  state_.mp_settings().mp_era_addon_id = (*eras_[era_index]->cfg)["addon_id"].str();
657 
658  return state_.mp_settings();
659 }
660 
662 {
663  if(const config& generic_multiplayer = game_config_manager::get()->game_config().child("generic_multiplayer")) {
664  config gen_mp_data = generic_multiplayer;
665 
666  // User maps.
667  int dep_index_offset = 0;
668  for(size_t i = 0; i < user_map_names_.size(); i++)
669  {
670  config user_map_data = gen_mp_data;
671  user_map_data["map_data"] = filesystem::read_map(user_map_names_[i]);
672 
673  // Check if a file is actually a map.
674  // Note that invalid maps should be displayed in order to
675  // show error messages in the GUI.
676  bool add_map = true;
677  std::unique_ptr<gamemap> map;
678  try {
679  map.reset(new gamemap(game_config_manager::get()->terrain_types(), user_map_data["map_data"]));
680  } catch (incorrect_map_format_error& e) {
681  user_map_data["description"] = _("Map could not be loaded: ") + e.message;
682 
683  ERR_CF << "map could not be loaded: " << e.message << '\n';
684  } catch (wml_exception&) {
685  add_map = false;
686  dep_index_offset++;
687  }
688 
689  if(add_map) {
690  type_map_[level::TYPE::USER_MAP].games.emplace_back(new user_map(user_map_data, user_map_names_[i], map.get()));
691 
692  // Since user maps are treated as scenarios, some dependency info is required
693  config depinfo;
694  depinfo["id"] = user_map_names_[i];
695  depinfo["name"] = user_map_names_[i];
696  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset);
697  }
698  }
699 
700  // User made scenarios.
701  dep_index_offset = 0;
702  for(size_t i = 0; i < user_scenario_names_.size(); i++)
703  {
704  config data;
705  try {
706  read(data, *preprocess_file(filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i]));
707  } catch (config::error & e) {
708  ERR_CF << "Caught a config error while parsing user made (editor) scenarios:\n" << e.message << std::endl;
709  ERR_CF << "Skipping file: " << (filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i]) << std::endl;
710  continue;
711  }
712 
713  scenario_ptr new_scenario(new scenario(data));
714  if(new_scenario->id().empty()) continue;
715 
716  type_map_[level::TYPE::USER_SCENARIO].games.push_back(std::move(new_scenario));
717 
718  // Since user scenarios are treated as scenarios, some dependency info is required
719  config depinfo;
720  depinfo["id"] = data["id"];
721  depinfo["name"] = data["name"];
722  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo, i - dep_index_offset++);
723  }
724  }
725 
726  // Stand-alone scenarios.
727  for(const config& data : game_config_manager::get()->game_config().child_range("multiplayer"))
728  {
729  if(!data["allow_new_game"].to_bool(true))
730  continue;
731 
732  if(!data["campaign_id"].empty())
733  continue;
734 
735  if(data.has_attribute("map_generation") || data.has_attribute("scenario_generation")) {
736  type_map_[level::TYPE::RANDOM_MAP].games.emplace_back(new random_map(data));
737  } else {
738  type_map_[level::TYPE::SCENARIO].games.emplace_back(new scenario(data));
739  }
740  }
741 
742  // Campaigns.
743  for(const config& data : game_config_manager::get()->game_config().child_range("campaign"))
744  {
745  const std::string& type = data["type"];
746  bool mp = state_.classification().campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
747 
748  if(type == "mp" || (type == "hybrid" && mp)) {
749  type_map_[level::TYPE::CAMPAIGN].games.emplace_back(new campaign(data));
750  }
751 
752  if(type == "sp" || type.empty() || (type == "hybrid" && !mp)) {
753  campaign_ptr new_sp_campaign(new campaign(data));
754  new_sp_campaign->mark_if_completed();
755 
756  type_map_[level::TYPE::SP_CAMPAIGN].games.push_back(std::move(new_sp_campaign));
757  }
758  }
759 
760  auto& sp_campaigns = type_map_[level::TYPE::SP_CAMPAIGN].games;
761 
762  // Sort sp campaigns by rank.
763  std::stable_sort(sp_campaigns.begin(), sp_campaigns.end(),
765  return a->data()["rank"].to_int(1000) < b->data()["rank"].to_int(1000);
766  }
767  );
768 }
769 
770 void create_engine::init_extras(const MP_EXTRA extra_type)
771 {
772  std::vector<extras_metadata_ptr>& extras = get_extras_by_type(extra_type);
773  const std::string extra_name = (extra_type == ERA) ? "era" : "modification";
774 
775  ng::depcheck::component_availability default_availabilty = (extra_type == ERA)
776  ? ng::depcheck::component_availability::MP
777  : ng::depcheck::component_availability::HYBRID;
778 
779  for(const config& extra : game_config_manager::get()->game_config().child_range(extra_name))
780  {
781  ng::depcheck::component_availability type = extra["type"].to_enum(default_availabilty);
782  bool mp = state_.classification().campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
783 
784  if((type != ng::depcheck::component_availability::MP || mp) && (type != ng::depcheck::component_availability::SP || !mp) )
785  {
786  extras_metadata_ptr new_extras_metadata(new extras_metadata());
787  new_extras_metadata->id = extra["id"].str();
788  new_extras_metadata->name = extra["name"].str();
789  new_extras_metadata->description = extra["description"].str();
790  new_extras_metadata->cfg = &extra;
791 
792  extras.push_back(std::move(new_extras_metadata));
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) const
805 {
806  std::vector<level_ptr> levels;
807  for(const level_ptr lvl : type_map_.at(type.v).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) const
815 {
816  auto& g_list = type_map_.at(type.v);
817 
818  std::vector<level_ptr> levels;
819  for(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.v).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
TYPE
UNSCALED : image will be drawn "as is" without changing size, even in case of redraw SCALED_TO_ZOOM :...
Definition: image.hpp:189
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:352
const char * what() const NOEXCEPT
Definition: exceptions.hpp:37
std::vector< char_t > string
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
saved_game & get_state()
std::vector< extras_metadata_ptr > mods_
bool can_launch_game() const
std::shared_ptr< level > level_ptr
std::shared_ptr< campaign > campaign_ptr
const std::vector< extras_metadata_ptr > & get_const_extras_by_type(const MP_EXTRA extra_type) const
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:217
std::vector< extras_metadata_ptr > & get_extras_by_type(const MP_EXTRA extra_type)
std::vector< level_ptr > get_levels_by_type(level::TYPE type) const
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:715
void set_scenario(config scenario)
Definition: saved_game.cpp:472
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
std::string generator_name() const
#define a
level & current_level() const
Definition: video.hpp:29
static lg::log_domain log_mp_create_engine("mp/create/engine")
bool is_campaign_completed(const std::string &campaign_id)
Definition: game.cpp:319
std::vector< std::string > user_scenario_names_
child_itors child_range(config_key_type key)
Definition: config.cpp:295
virtual bool allow_era_choice() const
std::vector< level_ptr > get_levels_by_type_unfiltered(level::TYPE type) const
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:401
std::shared_ptr< scenario > scenario_ptr
void clear()
Definition: saved_game.cpp:689
#define WRN_MP
bool generate_whole_scenario() const
void set_current_era_index(const size_t index, bool force=false)
void set_data(const config &data)
void clear()
Definition: config.cpp:742
#define d
static lg::log_domain log_config("config")
void set_current_level(const size_t index)
const config & data() const
bool empty() const
Definition: config.cpp:750
const mp_game_settings & get_parameters()
void prepare_for_era_and_mods()
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
bool current_level_has_side_data()
Returns true if the current level has one or more [side] tags.
bool generator_assigned() const
std::vector< std::pair< const std::string *, const stats * > > levels
Stats (and name) for each scenario. The pointers are never nullptr.
Definition: statistics.hpp:114
bool toggle_current_mod(bool force=false)
campaign(const config &data)
bool can_launch_game() const
std::string select_campaign_difficulty(int set_value=-1)
select_campaign_difficulty
#define b
std::map< level::TYPE, type_list > type_map_
static bool is_active(const widget *wgt)
Definition: window.cpp:1359
Pubic entry points for the MP workflow.
Definition: lobby_data.cpp:48
std::vector< extras_metadata_ptr > active_mods_data()
unsigned child_count(config_key_type key) const
Definition: config.cpp:323
std::vector< std::string > active_mods
static irdya_date read_date(const std::string &date)
static game_config_manager * get()
std::string selected_campaign_difficulty_
std::string level_name_filter_
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
std::pair< irdya_date, irdya_date > dates_
saved_game & state_
void set_metadata()
void prepare_for_campaign(const std::string &difficulty="")
#define DBG_MP
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:612
std::string get_user_data_dir()
std::unique_ptr< depcheck::manager > dependency_manager_
const extras_metadata & current_extra(const MP_EXTRA extra_type) const
const config & generator_data() const
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:41
Encapsulates the map of the game.
Definition: map.hpp:34
std::string end_text
end-of-campaign text
std::string campaign
the campaign being played
std::unique_ptr< gamemap > map_
std::string image_label_
std::vector< std::string > & active_mods()
void apply_level_filter(const std::string &name)
void init_generated_level_data()
int find_extra_by_id(const MP_EXTRA extra_type, 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.
map_generator * create_map_generator(const std::string &name, const config &cfg)
Definition: map_create.cpp:29
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:345
void mark_if_completed()
Helper class, don't construct this directly.
std::string login()
bool has_attribute(config_key_type key) const
Definition: config.cpp:196
std::string dev_message
The message for developers telling which problem was triggered, this shouldn't be translated...
std::string abbrev
the campaign abbreviation
scenario(const config &data)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs=nullptr, file_name_option mode=FILE_NAME_ONLY, file_filter_option filter=NO_FILTER, file_reorder_option reorder=DONT_REORDER, file_tree_checksum *checksum=nullptr)
Populates 'files' with all the files and 'dirs' with all the directories in dir.
level::TYPE find_level_type_by_id(const std::string &id) const
std::vector< std::string > campaign_xtra_defines
more customization of data
std::vector< size_t > get_filtered_level_indices(level::TYPE type) const
void load_game_config_for_create(bool is_mp, bool is_test=false)
std::string description() const
Game configuration data as global variables.
Definition: build_info.cpp:53
level(const config &data)
std::string mp_era_addon_id
const config & game_config() const
map_generator * create_map_generator() const
std::string scenario_define
If there is a define the scenario uses to customize data.
std::vector< std::string > mod_defines
If there are defines the modifications use to customize data.
#define i
bool show(CVideo &video, const unsigned auto_close_time=0)
Shows the window.
std::unique_ptr< map_generator > generator_
std::vector< std::string > user_map_names_
Declarations for File-IO.
config & add_child(config_key_type key)
Definition: config.cpp:408
std::string difficulty
The difficulty level the game is being played on.
std::string vgettext(const char *msgid, const utils::string_map &symbols)
std::shared_ptr< extras_metadata > extras_metadata_ptr
std::vector< extras_metadata_ptr > eras_
std::string hash() const
Definition: config.cpp:1176
bool generator_has_settings() const
const std::vector< std::string > & modifications(bool mp)
Definition: game.cpp:730
void load_game_config_for_game(const game_classification &classification)
random_map(const config &data)
game_classification & classification()
Definition: saved_game.hpp:55
void set_carryover_sides_start(config carryover_sides_start)
Definition: saved_game.cpp:124
Standard logging facilities (interface).
Base class for all level type classes.
std::string message
Definition: exceptions.hpp:31
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
#define e
const config & curent_era_cfg() const
int find_level_by_id(const std::string &id) const
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
std::string map_size() const
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
user_map(const config &data, const std::string &name, gamemap *map)
create_engine(CVideo &v, saved_game &state)
void init_extras(const MP_EXTRA extra_type)