The Battle for Wesnoth  1.13.4+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 - 2016 by Andrius Silinskas <[email protected]>
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 #include "create_engine.hpp"
15 
16 #include "depcheck.hpp"
17 #include "config_assign.hpp"
18 #include "game_config_manager.hpp"
19 #include "game_launcher.hpp"
20 #include "game_preferences.hpp"
23 #include "filesystem.hpp"
24 #include "formula/string_utils.hpp"
25 #include "hash.hpp"
26 #include "log.hpp"
28 #include "map/exception.hpp"
29 #include "marked-up_text.hpp"
30 #include "minimap.hpp"
31 #include "saved_game.hpp"
32 #include "wml_separators.hpp"
33 #include "wml_exception.hpp"
34 
36 #include "serialization/parser.hpp"
37 
38 #include <sstream>
39 #include <cctype>
40 
41 static lg::log_domain log_config("config");
42 #define ERR_CF LOG_STREAM(err, log_config)
43 
44 static lg::log_domain log_mp_create_engine("mp/create/engine");
45 #define WRN_MP LOG_STREAM(warn, log_mp_create_engine)
46 #define DBG_MP LOG_STREAM(debug, log_mp_create_engine)
47 
48 namespace {
49 bool contains_ignore_case(const std::string& str1, const std::string& str2)
50 {
51  if (str2.size() > str1.size()) {
52  return false;
53  }
54 
55  for (size_t i = 0; i<str1.size() - str2.size()+1; i++) {
56  bool ok = true;
57  for (size_t j = 0; j<str2.size(); j++) {
58  if (std::tolower(str1[i+j]) != std::tolower(str2[j])) {
59  ok = false;
60  break;
61  }
62  }
63 
64  if (ok) {
65  return true;
66  }
67  }
68 
69  return false;
70 }
71 }
72 
73 namespace ng {
74 
76  return a->data()["rank"].to_int(1000) < b->data()["rank"].to_int(1000);
77 }
78 
79 
81  data_(data)
82 {
83 }
84 
86 {
87  return data_["description"];
88 }
89 
91 {
92  return data_["name"];
93 }
94 
96 {
97  return data_["icon"];
98 }
99 
101 {
102  return data_["id"];
103 }
104 
106 {
107  return data_["allow_era_choice"].to_bool(true);
108 }
109 
111 {
112  data_ = data;
113 }
114 
115 const config& level::data() const
116 {
117  return data_;
118 }
119 
121 {
122  return data_;
123 }
124 
126  level(data),
127  map_(),
128  minimap_img_(),
129  map_hash_(),
130  num_players_(0)
131 {
132 }
133 
135 {
136 }
137 
139 {
140  return map_.get() != nullptr;
141 }
142 
143 surface scenario::create_image_surface(const SDL_Rect& image_rect)
144 {
145  if (!map_) {
146  minimap_img_ = surface();
147  return minimap_img_;
148  }
149 
150  std::string current_hash = util::encode_hash(util::md5(map_->write()));
151 
152  if (minimap_img_.null() || (map_hash_ != current_hash)) { // If there's no minimap image, or the map hash doesn't match, regenerate the image cache.
153  minimap_img_ = image::getMinimap(image_rect.w, image_rect.h, *map_, 0);
154  map_hash_ = current_hash;
155  }
156 
157  return minimap_img_;
158 }
159 
161 {
162  const std::string& map_data = data_["map_data"];
163 
164  try {
165  map_.reset(new gamemap(game_config_manager::get()->terrain_types(),
166  map_data));
167  } catch(incorrect_map_format_error& e) {
168  data_["description"] = _("Map could not be loaded: ") + e.message;
169 
170  ERR_CF << "map could not be loaded: " << e.message << '\n';
171  } catch(twml_exception& e) {
172  data_["description"] = _("Map could not be loaded.");
173 
174  ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
175  }
176 
177  set_sides();
178 }
179 
181 {
182  return num_players_;
183 }
184 
186 {
187  std::stringstream map_size;
188 
189  if (map_.get() != nullptr) {
190  map_size << map_.get()->w();
192  map_size << map_.get()->h();
193  } else {
194  map_size << _("not available.");
195  }
196 
197  return map_size.str();
198 }
199 
201 {
202  if (map_.get() != nullptr) {
203  // If there are less sides in the configuration than there are
204  // starting positions, then generate the additional sides
205  const int map_positions = map_->num_valid_starting_positions();
206 
207  for (int pos = data_.child_count("side");
208  pos < map_positions; ++pos) {
209  config& side = data_.add_child("side");
210  side["side"] = pos + 1;
211  side["team_name"] = "Team " + std::to_string(pos + 1);
212  side["canrecruit"] = true;
213  side["controller"] = "human";
214  }
215 
216  num_players_ = 0;
217  for (const config &scenario : data_.child_range("side")) {
218  if (scenario["allow_player"].to_bool(true)) {
219  ++num_players_;
220  }
221  }
222  }
223 }
224 
226  scenario(data),
227  name_(name)
228 {
229  if (map != nullptr) {
230  map_.reset(new gamemap(*map));
231  }
232 }
233 
235 {
236 }
237 
239 {
240  set_sides();
241 }
242 
244 {
245  if (data_["description"].empty()) {
246  return _("User made map");
247  } else { // map error message
248  return data_["description"];
249  }
250 }
251 
253 {
254  return name_;
255 }
256 
258 {
259  return name_;
260 }
261 
263  scenario(data),
264  generator_data_(),
265  generate_whole_scenario_(data_.has_attribute("scenario_generation")),
266  generator_name_(generate_whole_scenario_ ? data_["scenario_generation"] : data_["map_generation"])
267 {
268  if (!data.has_child("generator")) {
269  data_ = config();
271  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
272  data_["error_message"] = "missing [generator] tag";
273  } else {
274  generator_data_ = data.child("generator");
275  }
276 
277  if (!data.has_attribute("scenario_generation") && !data.has_attribute("map_generation")) {
278  data_ = config();
280  data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
281  data_["error_message"] = "couldn't find 'scenario_generation' or 'map_generation' attribute";
282  }
283 }
284 
286 {
287 }
288 
290 {
291  return generator_data_;
292 }
293 
295 {
296  return data_["name"];
297 }
298 
300 {
301  return data_["description"];
302 }
303 
305 {
306  return data_["id"];
307 }
308 
310 {
312 }
313 
315 {
316  return generator_name_;
317 }
318 
320 {
322 }
323 
325  level(data),
326  id_(data["id"]),
327  allow_era_choice_(level::allow_era_choice()),
328  image_label_(),
329  min_players_(2),
330  max_players_(2)
331 {
332 }
333 
335 {
336 }
337 
339 {
340  return !data_.empty();
341 }
342 
343 surface campaign::create_image_surface(const SDL_Rect& image_rect)
344 {
345  surface temp_image(
347 
348  return scale_surface(temp_image, image_rect.w, image_rect.h);
349 }
350 
352 {
353  image_label_ = data_["image"].str();
354 
355  int min = data_["min_players"].to_int(2);
356  int max = data_["max_players"].to_int(2);
357 
358  min_players_ = max_players_ = min;
359 
360  if (max > min) {
361  max_players_ = max;
362  }
363 }
364 
366 {
367  data_["completed"] = preferences::is_campaign_completed(data_["id"]);
368 }
369 
371 {
372  return id_;
373 }
374 
376 {
377  return allow_era_choice_;
378 }
379 
381 {
382  return min_players_;
383 }
384 
386 {
387  return max_players_;
388 }
389 
391  current_level_type_(),
392  current_level_index_(0),
393  current_era_index_(0),
394  current_mod_index_(0),
395  level_name_filter_(),
396  player_count_filter_(1),
397  scenarios_(),
398  user_maps_(),
399  user_scenarios_(),
400  campaigns_(),
401  sp_campaigns_(),
402  random_maps_(),
403  user_map_names_(),
404  user_scenario_names_(),
405  eras_(),
406  mods_(),
407  state_(state),
408  video_(v),
409  dependency_manager_(nullptr),
410  generator_(nullptr)
411 {
412  DBG_MP << "restoring game config\n";
413 
414  // Restore game config for multiplayer.
415  game_classification::CAMPAIGN_TYPE type = state_.classification().campaign_type;
417  state_ = saved_game();
418  state_.classification().campaign_type = type;
420  game_config_manager::get()->load_game_config_for_create(type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER);
421  //Initilialize dependency_manager_ after refreshing game config.
422  dependency_manager_.reset(new depcheck::manager(game_config_manager::get()->game_config(), type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER, video_));
423  //TODO the editor dir is already configurable, is the preferences value
425  nullptr, filesystem::FILE_NAME_ONLY);
426 
428  nullptr, filesystem::FILE_NAME_ONLY);
429 
430  DBG_MP << "initializing all levels, eras and mods\n";
431 
432  init_all_levels();
433  init_extras(ERA);
434  init_extras(MOD);
435 
436  state_.mp_settings().saved_game = false;
437 
438  for (const std::string& str : preferences::modifications(state_.classification().campaign_type ==
439  game_classification::CAMPAIGN_TYPE::MULTIPLAYER)) {
441  game_config().find_child("modification", "id", str))
442  state_.mp_settings().active_mods.push_back(str);
443  }
444 
445  if (current_level_type_ != level::TYPE::CAMPAIGN &&
446  current_level_type_ != level::TYPE::SP_CAMPAIGN) {
447  dependency_manager_->try_modifications(state_.mp_settings().active_mods, true);
448  }
449 
451 }
452 
454 {
455 }
456 
458 {
459  DBG_MP << "initializing generated level data\n";
460 
461  //DBG_MP << "current data:\n";
462  //DBG_MP << current_level().data().debug();
463 
464  random_map * cur_lev = dynamic_cast<random_map *> (&current_level());
465 
466  if (!cur_lev) {
467  WRN_MP << "Tried to initialized generated level data on a level that wasn't a random map\n";
468  return;
469  }
470 
471  try {
472  if (!cur_lev->generate_whole_scenario())
473  {
474  DBG_MP << "** replacing map ** \n";
475 
476  config data = cur_lev->data();
477 
478  data["map_data"] = generator_->create_map();
479 
480  cur_lev->set_data(data);
481 
482  } else { //scenario generation
483 
484  DBG_MP << "** replacing scenario ** \n";
485 
486  config data = generator_->create_scenario();
487 
488  // Set the scenario to have placing of sides
489  // based on the terrain they prefer
490  if (!data.has_attribute("modify_placing")) {
491  data["modify_placing"] = "true";
492  }
493 
494  const std::string& description = cur_lev->data()["description"];
495  data["description"] = description;
496 
497  cur_lev->set_data(data);
498  }
499  } catch (mapgen_exception & e) {
500  config data = cur_lev->data();
501 
502  data["error_message"] = e.what();
503 
504  cur_lev->set_data(data);
505  }
506 
507  //DBG_MP << "final data:\n";
508  //DBG_MP << current_level().data().debug();
509 
510 }
511 
513 {
514  DBG_MP << "preparing mp_game_settings for new level\n";
517 }
518 
520 {
523  "era", "id", get_parameters().mp_era)["define"].str();
524  for (const std::string& mod_id : get_parameters().active_mods) {
525  state_.classification().mod_defines.push_back(
526  game_config_manager::get()->game_config().find_child(
527  "modification", "id", mod_id)["define"].str());
528  }
529 }
530 
532 {
533  DBG_MP << "preparing data for scenario by reloading game config\n";
534 
536  current_level().data()["define"].str();
537 
539  config_of("next_scenario", current_level().data()["id"])
540  );
541 }
542 
544 {
545  DBG_MP << "preparing data for campaign by reloading game config\n";
546 
547  if (difficulty != "") {
548  state_.classification().difficulty = difficulty;
549  }
550 
551  state_.classification().campaign = current_level().data()["id"].str();
552  state_.classification().abbrev = current_level().data()["abbrev"].str();
553 
554  state_.classification().end_text = current_level().data()["end_text"].str();
556  current_level().data()["end_text_duration"];
557 
559  current_level().data()["define"].str();
561  utils::split(current_level().data()["extra_defines"]);
562 
564  config_of("next_scenario", current_level().data()["first_scenario"])
565  );
566 }
567 
568 /**
569  * select_campaign_difficulty
570  *
571  * Launches difficulty selection gui and returns selected difficulty name.
572  *
573  * The gui can be bypassed by supplying a number from 1 to the number of
574  * difficulties available, corresponding to a choice of difficulty.
575  * This is useful for specifying difficulty via command line.
576  *
577  * @param set_value Preselected difficulty number. The default -1 launches the gui.
578  * @return Selected difficulty. Returns "FAIL" if set_value is invalid,
579  * and "CANCEL" if the gui is canceled.
580  */
582 {
583  // Verify the existence of difficulties
584  std::vector<std::string> difficulties;
585 
586  for (const config &d : current_level().data().child_range("difficulty"))
587  {
588  difficulties.push_back(d["define"]);
589  }
590 
591  if(difficulties.empty()) {
592  difficulties = utils::split(current_level().data()["difficulties"]);
593  }
594 
595  // No difficulties found. Exit
596  if(difficulties.empty()) {
597  return "";
598  }
599 
600  // A specific difficulty value was passed
601  // Use a minimilistic interface to get the specified define
602  if(set_value != -1) {
603  if (set_value > static_cast<int>(difficulties.size())) {
604  std::cerr << "incorrect difficulty number: [" <<
605  set_value << "]. maximum is [" << difficulties.size() << "].\n";
606  return "FAIL";
607  } else if (set_value < 1) {
608  std::cerr << "incorrect difficulty number: [" <<
609  set_value << "]. minimum is [1].\n";
610  return "FAIL";
611  } else {
612  return difficulties[set_value - 1];
613  }
614  }
615 
616  // If not, let the user pick one from the prompt
617  // We don't pass the difficulties vector here because additional data is required
618  // to constrict the dialog
620  dlg.show(video_);
621 
622  return dlg.selected_difficulty();
623 }
624 
626 {
627  DBG_MP << "preparing mp_game_settings for saved game\n";
628 
630  //The save migh be a start-of-scenario save so make sure we have the scenario data loaded.
632  state_.mp_settings().saved_game = true;
633 
634  utils::string_map i18n_symbols;
635  i18n_symbols["login"] = preferences::login();
636  state_.mp_settings().name = vgettext("$login|’s game", i18n_symbols);
637 }
638 
640 {
641  DBG_MP << "prepare_for_other\n";
644 }
645 
647 {
650 }
651 
653 {
654  player_count_filter_ = players;
656 }
657 
659 {
660  scenarios_filtered_.clear();
661  for (size_t i = 0; i<scenarios_.size(); i++) {
662  scenarios_filtered_.push_back(i);
663  }
664 
665  user_scenarios_filtered_.clear();
666  for (size_t i = 0; i<user_scenarios_.size(); i++) {
667  user_scenarios_filtered_.push_back(i);
668  }
669 
670  user_maps_filtered_.clear();
671  for (size_t i = 0; i<user_maps_.size(); i++) {
672  user_maps_filtered_.push_back(i);
673  }
674 
675  campaigns_filtered_.clear();
676  for (size_t i = 0; i<campaigns_.size(); i++) {
677  campaigns_filtered_.push_back(i);
678  }
679 
680  sp_campaigns_filtered_.clear();
681  for (size_t i = 0; i<sp_campaigns_.size(); i++) {
682  sp_campaigns_filtered_.push_back(i);
683  }
684 
685  random_maps_filtered_.clear();
686  for (size_t i = 0; i<random_maps_.size(); i++) {
687  random_maps_filtered_.push_back(i);
688  }
689 
690  level_name_filter_ = "";
691 }
692 
694 {
695  return level_name_filter_;
696 }
697 
699 {
700  return player_count_filter_;
701 }
702 
703 std::vector<std::string> create_engine::levels_menu_item_names() const
704 {
705  std::vector<std::string> menu_names;
706 
708  menu_names.push_back(IMAGE_PREFIX + level->icon() + IMG_TEXT_SEPARATOR + level->name()
710  }
711 
712  return menu_names;
713 }
714 
715 std::vector<std::string> create_engine::extras_menu_item_names(
716  const MP_EXTRA extra_type, bool escape_markup) const
717 {
718  std::vector<std::string> names;
719 
720  for (extras_metadata_ptr extra : get_const_extras_by_type(extra_type)) {
721  if (escape_markup) {
722  names.push_back(font::NULL_MARKUP + extra->name);
723  } else {
724  names.push_back(extra->name);
725  }
726  }
727 
728  return names;
729 }
730 
732 {
733  switch (current_level_type_.v) {
734  case level::TYPE::SCENARIO: {
736  }
737  case level::TYPE::USER_SCENARIO: {
739  }
740  case level::TYPE::USER_MAP: {
742  }
743  case level::TYPE::RANDOM_MAP: {
745  }
746  case level::TYPE::CAMPAIGN: {
748  }
749  case level::TYPE::SP_CAMPAIGN:
750  default: {
752  }
753  } // end switch
754 }
755 
757  const MP_EXTRA extra_type) const
758 {
759  const size_t index = (extra_type == ERA) ?
761 
762  return *get_const_extras_by_type(extra_type)[index];
763 }
764 
766 {
768 }
769 
771 {
772  return current_level_type_;
773 }
774 
776 {
777  switch (current_level_type().v) {
778  case level::TYPE::CAMPAIGN:
780  break;
781  case level::TYPE::SP_CAMPAIGN:
783  break;
786  break;
787  case level::TYPE::RANDOM_MAP:
789  break;
790  case level::TYPE::USER_MAP:
792  break;
793  case level::TYPE::USER_SCENARIO:
795  }
796 
797  if (current_level_type_ == level::TYPE::RANDOM_MAP) {
798  random_map* current_random_map =
799  dynamic_cast<random_map*>(&current_level());
800 
801  assert(current_random_map); // if dynamic cast has failed then we somehow have gotten all the pointers mixed together.
802 
803  generator_.reset(current_random_map->create_map_generator());
804  } else {
805  generator_.reset(nullptr);
806  }
807 
808  if (current_level_type_ != level::TYPE::CAMPAIGN &&
809  current_level_type_ != level::TYPE::SP_CAMPAIGN) {
810 
811  dependency_manager_->try_scenario(current_level().id());
812  }
813 }
814 
815 void create_engine::set_current_era_index(const size_t index, bool force)
816 {
818 
819  dependency_manager_->try_era_by_index(index, force);
820 }
821 
823 {
825 }
826 
828 {
829  return current_era_index_;
830 }
831 
833 {
834  return current_mod_index_;
835 }
836 
838 {
839  force |= (current_level_type_ == ng::level::TYPE::CAMPAIGN || current_level_type_ == ng::level::TYPE::SP_CAMPAIGN);
840  bool is_active = dependency_manager_->is_modification_active(current_mod_index_);
841  dependency_manager_->try_modification_by_index(current_mod_index_, !is_active, force);
842 
843  state_.mp_settings().active_mods = dependency_manager_->get_modifications();
844 
845  return !is_active;
846 }
847 
849 {
850  return generator_ != nullptr;
851 }
852 
854 {
855  generator_->user_config(v);
856 }
857 
859 {
860  int i = 0;
862  if (user_map->id() == id) {
863  return i;
864  }
865  i++;
866  }
867 
868  i = 0;
870  if (random_map->id() == id) {
871  return i;
872  }
873  i++;
874  }
875 
876  i = 0;
878  if (scenario->id() == id) {
879  return i;
880  }
881  i++;
882  }
883 
884  i = 0;
886  if (scenario->id() == id) {
887  return i;
888  }
889  i++;
890  }
891 
892  i = 0;
894  if (campaign->id() == id) {
895  return i;
896  }
897  i++;
898  }
899 
900  i = 0;
901  for (campaign_ptr sp_campaign : sp_campaigns_) {
902  if (sp_campaign->id() == id) {
903  return i;
904  }
905  i++;
906  }
907 
908  return -1;
909 }
910 
912  const std::string& id) const
913 {
914  int i = 0;
915  for (extras_metadata_ptr extra : get_const_extras_by_type(extra_type)) {
916  if (extra->id == id) {
917  return i;
918  }
919  i++;
920  }
921 
922  return -1;
923 }
924 
926 {
928  if (user_map->id() == id) {
929  return level::TYPE::USER_MAP;
930  }
931  }
933  if (random_map->id() == id) {
934  return level::TYPE::RANDOM_MAP;
935  }
936  }
938  if (scenario->id() == id) {
939  return level::TYPE::SCENARIO;
940  }
941  }
943  if (scenario->id() == id) {
944  return level::TYPE::USER_SCENARIO;
945  }
946  }
948  if (campaign->id() == id) {
949  return level::TYPE::CAMPAIGN;
950  }
951  }
952  return level::TYPE::SP_CAMPAIGN;
953 }
954 
955 const depcheck::manager& create_engine::dependency_manager() const
956 {
957  return *dependency_manager_;
958 }
959 
961 {
962  state_.mp_settings().active_mods = dependency_manager_->get_modifications();
963 }
964 
965 std::vector<std::string>& create_engine::active_mods()
966 {
967  return state_.mp_settings().active_mods;
968 }
969 
971 {
972  DBG_MP << "getting parameter values" << std::endl;
973 
974  int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
975  state_.mp_settings().mp_era = eras_[era_index]->id;
976 
977  return state_.mp_settings();
978 }
979 
981 {
982  if (const config &generic_multiplayer =
984  "generic_multiplayer")) {
985  config gen_mp_data = generic_multiplayer;
986 
987  // User maps.
988  int dep_index_offset = 0;
989  for(size_t i = 0; i < user_map_names_.size(); i++)
990  {
991  config user_map_data = gen_mp_data;
992  user_map_data["map_data"] = filesystem::read_map(user_map_names_[i]);
993 
994  // Check if a file is actually a map.
995  // Note that invalid maps should be displayed in order to
996  // show error messages in the GUI.
997  bool add_map = true;
998  boost::scoped_ptr<gamemap> map;
999  try {
1000  map.reset(new gamemap(game_config_manager::get()->terrain_types(),
1001  user_map_data["map_data"]));
1002  } catch (incorrect_map_format_error& e) {
1003  user_map_data["description"] = _("Map could not be loaded: ") +
1004  e.message;
1005 
1006  ERR_CF << "map could not be loaded: " << e.message << '\n';
1007  } catch (twml_exception&) {
1008  add_map = false;
1009  dep_index_offset++;
1010  }
1011 
1012  if (add_map) {
1013  user_map_ptr new_user_map(new user_map(user_map_data,
1014  user_map_names_[i], map.get()));
1015  user_maps_.push_back(new_user_map);
1016  user_maps_.back()->set_metadata();
1017 
1018  // Since user maps are treated as scenarios,
1019  // some dependency info is required
1020  config depinfo;
1021  depinfo["id"] = user_map_names_[i];
1022  depinfo["name"] = user_map_names_[i];
1023  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo,
1024  i - dep_index_offset);
1025  }
1026  }
1027 
1028  // User made scenarios.
1029  dep_index_offset = 0;
1030  for(size_t i = 0; i < user_scenario_names_.size(); i++)
1031  {
1032  config data;
1033  try {
1034  read(data, *(preprocess_file(filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i])));
1035  } catch (config::error & e) {
1036  ERR_CF << "Caught a config error while parsing user made (editor) scenarios:\n" << e.message << std::endl;
1037  ERR_CF << "Skipping file: " << (filesystem::get_user_data_dir() + "/editor/scenarios/" + user_scenario_names_[i]) << std::endl;
1038  continue;
1039  }
1040 
1041  scenario_ptr new_scenario(new scenario(data));
1042  if (new_scenario->id().empty()) continue;
1043  user_scenarios_.push_back(new_scenario);
1044  user_scenarios_.back()->set_metadata();
1045 
1046  // Since user scenarios are treated as scenarios,
1047  // some dependency info is required
1048  config depinfo;
1049  depinfo["id"] = data["id"];
1050  depinfo["name"] = data["name"];
1051  dependency_manager_->insert_element(depcheck::SCENARIO, depinfo,
1052  i - dep_index_offset++);
1053  }
1054  }
1055 
1056  // Stand-alone scenarios.
1057  for (const config &data : game_config_manager::get()->game_config().child_range("multiplayer"))
1058  {
1059  if (!data["allow_new_game"].to_bool(true))
1060  continue;
1061 
1062  if (!data["campaign_id"].empty())
1063  continue;
1064 
1065  if (data.has_attribute("map_generation") || data.has_attribute("scenario_generation")) {
1066  random_map_ptr new_random_map(new random_map(data));
1067  random_maps_.push_back(new_random_map);
1068  random_maps_.back()->set_metadata();
1069  } else {
1070  scenario_ptr new_scenario(new scenario(data));
1071  scenarios_.push_back(new_scenario);
1072  scenarios_.back()->set_metadata();
1073  }
1074  }
1075 
1076  // Campaigns.
1077  for (const config &data : game_config_manager::get()->game_config().child_range("campaign"))
1078  {
1079  const std::string& type = data["type"];
1080  bool mp = state_.classification().campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
1081 
1082  if (type == "mp" || (type == "hybrid" && mp)) {
1083  campaign_ptr new_campaign(new campaign(data));
1084  campaigns_.push_back(new_campaign);
1085  campaigns_.back()->set_metadata();
1086  }
1087  if (type == "sp" || type.empty() || (type == "hybrid" && !mp)) {
1088  campaign_ptr new_sp_campaign(new campaign(data));
1089  sp_campaigns_.push_back(new_sp_campaign);
1090  sp_campaigns_.back()->set_metadata();
1091  sp_campaigns_.back()->mark_if_completed();
1092  }
1093  }
1094 
1095  // Sort sp campaigns by rank.
1096  std::stable_sort(sp_campaigns_.begin(),sp_campaigns_.end(),less_campaigns_rank);
1097 }
1098 
1099 void create_engine::init_extras(const MP_EXTRA extra_type)
1100 {
1101  std::vector<extras_metadata_ptr>& extras = get_extras_by_type(extra_type);
1102  const std::string extra_name = (extra_type == ERA) ? "era" : "modification";
1103  ng::depcheck::component_availabilty default_availabilty = (extra_type == ERA) ? ng::depcheck::component_availabilty::MP : ng::depcheck::component_availabilty::HYBRID;
1104  for (const config &extra : game_config_manager::get()->game_config().child_range(extra_name))
1105  {
1106  ng::depcheck::component_availabilty type = extra["type"].to_enum(default_availabilty);
1107  bool mp = state_.classification().campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
1108 
1109  if((type != ng::depcheck::component_availabilty::MP || mp) && (type != ng::depcheck::component_availabilty::SP || !mp) )
1110  {
1111  extras_metadata_ptr new_extras_metadata(new extras_metadata());
1112  new_extras_metadata->id = extra["id"].str();
1113  new_extras_metadata->name = extra["name"].str();
1114  new_extras_metadata->description = extra["description"].str();
1115 
1116  extras.push_back(new_extras_metadata);
1117  }
1118  }
1119 }
1120 
1122 {
1123  scenarios_filtered_.clear();
1124  for (size_t i = 0; i<scenarios_.size(); i++) {
1125  if (contains_ignore_case(scenarios_[i]->name(), level_name_filter_) &&
1126  (player_count_filter_ == 1 ||
1127  scenarios_[i]->num_players() == player_count_filter_)) {
1128  scenarios_filtered_.push_back(i);
1129  }
1130  }
1131 
1132  user_scenarios_filtered_.clear();
1133  for (size_t i = 0; i<user_scenarios_.size(); i++) {
1134  if (contains_ignore_case(user_scenarios_[i]->name(), level_name_filter_) &&
1135  (player_count_filter_ == 1 ||
1136  user_scenarios_[i]->num_players() == player_count_filter_)) {
1137  user_scenarios_filtered_.push_back(i);
1138  }
1139  }
1140 
1141  user_maps_filtered_.clear();
1142  for (size_t i = 0; i<user_maps_.size(); i++) {
1143  if (contains_ignore_case(user_maps_[i]->name(), level_name_filter_) &&
1144  (player_count_filter_ == 1 ||
1145  user_maps_[i]->num_players() == player_count_filter_)) {
1146  user_maps_filtered_.push_back(i);
1147  }
1148  }
1149 
1150  campaigns_filtered_.clear();
1151  for (size_t i = 0; i<campaigns_.size(); i++) {
1152  if (contains_ignore_case(campaigns_[i]->name(), level_name_filter_) &&
1153  (player_count_filter_ == 1 ||
1154  (campaigns_[i]->min_players() <= player_count_filter_ &&
1155  campaigns_[i]->max_players() >= player_count_filter_))) {
1156  campaigns_filtered_.push_back(i);
1157  }
1158  }
1159 
1160  sp_campaigns_filtered_.clear();
1161  for (size_t i = 0; i<sp_campaigns_.size(); i++) {
1162  if (contains_ignore_case(sp_campaigns_[i]->name(), level_name_filter_) &&
1163  (player_count_filter_ == 1 ||
1164  (sp_campaigns_[i]->min_players() <= player_count_filter_ &&
1165  sp_campaigns_[i]->max_players() >= player_count_filter_))) {
1166  sp_campaigns_filtered_.push_back(i);
1167  }
1168  }
1169 
1170  random_maps_filtered_.clear();
1171  for (size_t i = 0; i<random_maps_.size(); i++) {
1172  if (contains_ignore_case(random_maps_[i]->name(), level_name_filter_) &&
1173  (player_count_filter_ == 1 ||
1174  random_maps_[i]->num_players() == player_count_filter_)) {
1175  random_maps_filtered_.push_back(i);
1176  }
1177  }
1178 
1179 }
1180 
1181 std::vector<create_engine::level_ptr>
1183 {
1184  std::vector<level_ptr> levels;
1185  switch (type.v) {
1186  case level::TYPE::SCENARIO:
1187  for (level_ptr level : scenarios_) {
1188  levels.push_back(level);
1189  }
1190  break;
1191  case level::TYPE::USER_MAP:
1192  for (level_ptr level : user_maps_) {
1193  levels.push_back(level);
1194  }
1195  break;
1196  case level::TYPE::USER_SCENARIO:
1197  for (level_ptr level : user_scenarios_) {
1198  levels.push_back(level);
1199  }
1200  break;
1201  case level::TYPE::RANDOM_MAP:
1202  for (level_ptr level : random_maps_) {
1203  levels.push_back(level);
1204  }
1205  break;
1206  case level::TYPE::CAMPAIGN:
1207  for (level_ptr level : campaigns_) {
1208  levels.push_back(level);
1209  }
1210  break;
1211  case level::TYPE::SP_CAMPAIGN:
1212  for (level_ptr level : sp_campaigns_) {
1213  levels.push_back(level);
1214  }
1215  break;
1216  } // end switch
1217 
1218  return levels;
1219 }
1220 
1221 std::vector<create_engine::level_ptr> create_engine::get_levels_by_type(level::TYPE type) const
1222 {
1223  std::vector<level_ptr> levels;
1224  switch (type.v) {
1225  case level::TYPE::SCENARIO:
1226  for (size_t level : scenarios_filtered_) {
1227  levels.push_back(scenarios_[level]);
1228  }
1229  break;
1230  case level::TYPE::USER_MAP:
1231  for (size_t level : user_maps_filtered_) {
1232  levels.push_back(user_maps_[level]);
1233  }
1234  break;
1235  case level::TYPE::USER_SCENARIO:
1236  for (size_t level : user_scenarios_filtered_) {
1237  levels.push_back(user_scenarios_[level]);
1238  }
1239  break;
1240  case level::TYPE::RANDOM_MAP:
1241  for (size_t level : random_maps_filtered_) {
1242  levels.push_back(random_maps_[level]);
1243  }
1244  break;
1245  case level::TYPE::CAMPAIGN:
1246  for (size_t level : campaigns_filtered_) {
1247  levels.push_back(campaigns_[level]);
1248  }
1249  break;
1250  case level::TYPE::SP_CAMPAIGN:
1251  for (size_t level : sp_campaigns_filtered_) {
1252  levels.push_back(sp_campaigns_[level]);
1253  }
1254  break;
1255  } // end switch
1256 
1257  return levels;
1258 }
1259 
1260 const std::vector<create_engine::extras_metadata_ptr>&
1262 {
1263  return (extra_type == ERA) ? eras_ : mods_;
1264 }
1265 
1266 std::vector<create_engine::extras_metadata_ptr>&
1268 {
1269  return (extra_type == ERA) ? eras_ : mods_;
1270 }
1271 
1273 {
1274  return state_;
1275 }
1276 
1277 } // end namespace ng
void set_current_mod_index(const size_t index)
config data_
TYPE
UNSCALED : image will be drawn "as is" without changing size, even in case of redraw SCALED_TO_ZOOM :...
Definition: image.hpp:208
std::vector< std::string > levels_menu_item_names() const
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
child_itors child_range(const std::string &key)
Definition: config.cpp:613
unsigned int end_text_duration
for how long the end-of-campaign text is shown
#define ERR_CF
surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::map< map_location, unsigned int > *reach_map)
function to create the minimap for a given map the surface returned must be freed by the user ...
Definition: minimap.cpp:43
char const IMG_TEXT_SEPARATOR
bool null() const
Definition: utils.hpp:104
saved_game & get_state()
std::vector< extras_metadata_ptr > mods_
bool can_launch_game() const
std::string id_
Definition: formula.cpp:636
virtual ~user_map()
const depcheck::manager & dependency_manager() const
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:204
const char * what() const
Definition: exceptions.hpp:35
int pos
Definition: formula.cpp:800
std::vector< extras_metadata_ptr > & get_extras_by_type(const MP_EXTRA extra_type)
int player_num_filter() const
std::vector< level_ptr > get_levels_by_type(level::TYPE type) const
void set_scenario(config scenario)
Definition: saved_game.cpp:458
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
std::string generator_name() const
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
variant map_
Definition: formula.cpp:306
bool show(CVideo &video, const unsigned auto_close_time=0)
Shows the window.
Definition: dialog.cpp:34
level & current_level() const
Definition: video.hpp:58
virtual std::string name() const
static lg::log_domain log_mp_create_engine("mp/create/engine")
bool is_campaign_completed(const std::string &campaign_id)
std::vector< std::string > user_scenario_names_
void generator_user_config(CVideo &v)
std::string id() 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:387
bool generate_whole_scenario_
int min_players() const
std::vector< size_t > user_maps_filtered_
size_t current_era_index() const
#define WRN_MP
bool generate_whole_scenario() const
void set_current_era_index(const size_t index, bool force=false)
const std::string unicode_multiplication_sign
std::array< uint8_t, 16 > md5(const std::string &input)
Returns the MD5 digest for the specified input.
Definition: hash.cpp:26
void set_data(const config &data)
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
surface create_image_surface(const SDL_Rect &image_rect)
#define d
static lg::log_domain log_config("config")
void set_current_level(const size_t index)
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
std::vector< random_map_ptr > random_maps_
bool empty() const
Definition: config.cpp:1105
const mp_game_settings & get_parameters()
void prepare_for_era_and_mods()
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:115
bool toggle_current_mod(bool force=false)
char const IMAGE_PREFIX
campaign(const config &data)
bool can_launch_game() const
std::string select_campaign_difficulty(int set_value=-1)
select_campaign_difficulty
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
This module controls the multiplayer lobby.
bool has_child(const std::string &key) const
Determine whether a config has a child or not.
Definition: config.cpp:651
std::vector< size_t > scenarios_filtered_
virtual ~random_map()
std::vector< std::string > active_mods
static game_config_manager * get()
std::string level_name_filter_
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
virtual ~campaign()
std::map< std::string, t_string > string_map
saved_game & state_
std::vector< scenario_ptr > scenarios_
GLuint id
Definition: glew.h:1647
char const HELP_STRING_SEPARATOR
const config & generator_data() const
#define DBG_MP
std::string get_user_data_dir()
const extras_metadata & current_extra(const MP_EXTRA extra_type) const
const GLdouble * v
Definition: glew.h:1359
std::string campaign_define
If there is a define the campaign uses to customize data.
size_t current_mod_index() const
std::string name() const
level::TYPE current_level_type_
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
std::string dev_message
The message for developers telling which problem was triggered, this shouldn't be translated...
Encapsulates the map of the game.
Definition: map.hpp:37
config & add_child(const std::string &key)
Definition: config.cpp:743
std::string end_text
end-of-campaign text
static bool less_campaigns_rank(const create_engine::level_ptr &a, const create_engine::level_ptr &b)
const config & data() const
std::vector< size_t > random_maps_filtered_
std::string campaign
the campaign being played
std::string image_label_
GLuint const GLuint * names
Definition: glew.h:2552
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.
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
map_generator * create_map_generator(const std::string &name, const config &cfg)
Definition: map_create.cpp:31
virtual bool allow_era_choice() const
std::string map_hash_
void mark_if_completed()
std::vector< campaign_ptr > sp_campaigns_
void load_game_config_for_create(bool is_mp)
std::string login()
std::vector< user_map_ptr > user_maps_
std::string abbrev
the campaign abbreviation
scenario(const config &data)
std::vector< std::string > extras_menu_item_names(const MP_EXTRA extra_type, bool escape_markup=true) const
const char NULL_MARKUP
std::string id() const
bool allow_era_choice() const
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.
surface create_image_surface(const SDL_Rect &image_rect)
level::TYPE find_level_type_by_id(const std::string &id) const
std::vector< std::string > campaign_xtra_defines
more customization of data
std::string description() const
Game configuration data as global variables.
Definition: build_info.cpp:38
level(const config &data)
std::string encode_hash(const std::array< uint8_t, 16 > &input)
Definition: hash.cpp:51
const config & game_config() const
GLuint index
Definition: glew.h:1782
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.
size_t i
Definition: function.cpp:1057
std::vector< std::string > user_map_names_
Declarations for File-IO.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:400
void prepare_for_campaign(const std::string &difficulty)
boost::scoped_ptr< depcheck::manager > dependency_manager_
std::vector< size_t > sp_campaigns_filtered_
const std::string & level_name_filter() const
level::TYPE current_level_type() const
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
std::vector< scenario_ptr > user_scenarios_
std::string difficulty
The difficulty level the game is being played on.
std::string vgettext(const char *msgid, const utils::string_map &symbols)
std::string description() const
GLuint const GLchar * name
Definition: glew.h:1782
std::string name_
std::vector< extras_metadata_ptr > eras_
std::string hash() const
Definition: config.cpp:1468
std::istream * preprocess_file(std::string const &fname, preproc_map *defines)
boost::scoped_ptr< gamemap > map_
connection connect(const std::string &host, int port)
Function to attempt to connect to a remote host.
Definition: network.cpp:498
const std::vector< std::string > & modifications(bool mp)
std::vector< size_t > campaigns_filtered_
void load_game_config_for_game(const game_classification &classification)
int max_players() const
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
random_map(const config &data)
virtual ~scenario()
game_classification & classification()
Definition: saved_game.hpp:54
void set_carryover_sides_start(config carryover_sides_start)
Definition: saved_game.cpp:113
config & child(const std::string &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:658
config & find_child(const std::string &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:1010
std::string id() const
Standard logging facilities (interface).
std::string id_
virtual std::string description() const
void set_current_level_type(const level::TYPE)
std::string message
Definition: exceptions.hpp:29
virtual std::string icon() const
surface minimap_img_
int num_players() const
std::vector< size_t > user_scenarios_filtered_
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
#define e
virtual std::string id() const
std::string generator_name_
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:83
Helper class, don't construct this directly.
std::string map_size() const
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:58
GLsizei const GLcharARB ** string
Definition: glew.h:4503
user_map(const config &data, const std::string &name, gamemap *map)
create_engine(CVideo &v, saved_game &state)
std::string name() const
std::vector< campaign_ptr > campaigns_
boost::scoped_ptr< map_generator > generator_
void init_extras(const MP_EXTRA extra_type)