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