The Battle for Wesnoth  1.17.23+dev
depcheck.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2023
3  by Boldizsár Lipka <lipkab@zoho.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 <algorithm>
19 
22 #include "gettext.hpp"
23 #include "log.hpp"
24 #include "utils/general.hpp"
25 
28 #include "gui/dialogs/message.hpp"
29 #include "game_config_view.hpp"
30 
31 static lg::log_domain log_mp_create_depcheck("mp/create/depcheck");
32 #define DBG_MP LOG_STREAM(debug, log_mp_create_depcheck)
33 
34 namespace
35 {
36 // helper function
37 void copy_keys(config& out, const config& in, const std::string& type, bool copy_force_key = false)
38 {
39  if(in.has_attribute("allow_" + type)) {
40  out["allow_" + type] = in["allow_" + type];
41  } else if(in.has_attribute("disallow_" + type)) {
42  out["disallow_" + type] = in["disallow_" + type];
43  }
44 
45  if(in.has_attribute("ignore_incompatible_" + type)) {
46  out["ignore_incompatible_" + type] = in["ignore_incompatible_" + type];
47  }
48 
49  if(copy_force_key) {
50  if(in.has_attribute("force_" + type)) {
51  out["force_" + type] = in["force_" + type];
52  }
53  }
54 }
55 } // anonymous namespace
56 
57 namespace ng
58 {
59 namespace depcheck
60 {
61 manager::manager(const game_config_view& gamecfg, bool mp)
62  : depinfo_()
63  , era_()
64  , scenario_()
65  , mods_()
66  , prev_era_()
67  , prev_scenario_()
68  , prev_mods_()
69 {
70  DBG_MP << "Initializing the dependency manager";
71 
72  for(const config& cfg : gamecfg.child_range("modification")) {
73  component_availability::type type = component_availability::get_enum(cfg["type"].str()).value_or(component_availability::type::hybrid);
74 
75  if((type != component_availability::type::mp || mp) && (type != component_availability::type::sp || !mp)) {
76  config info;
77  info["id"] = cfg["id"];
78  info["name"] = cfg["name"];
79 
80  copy_keys(info, cfg, "scenario");
81  copy_keys(info, cfg, "era");
82  copy_keys(info, cfg, "modification");
83 
84  depinfo_.add_child("modification", std::move(info));
85  }
86  }
87 
88  for(const config& cfg : gamecfg.child_range("era")) {
89  component_availability::type type = component_availability::get_enum(cfg["type"].str()).value_or(component_availability::type::mp);
90 
91  if((type != component_availability::type::mp || mp) && (type != component_availability::type::sp || !mp)) {
92  config info;
93  info["id"] = cfg["id"];
94  info["name"] = cfg["name"];
95 
96  copy_keys(info, cfg, "scenario");
97  copy_keys(info, cfg, "modification", true);
98 
99  depinfo_.add_child("era", std::move(info));
100  }
101  }
102 
103  for(const config& cfg : gamecfg.child_range("multiplayer")) {
104  if(cfg["allow_new_game"].to_bool(true)) {
105  config info;
106  info["id"] = cfg["id"];
107  info["name"] = cfg["name"];
108 
109  copy_keys(info, cfg, "era");
110  copy_keys(info, cfg, "modification", true);
111 
112  depinfo_.add_child("scenario", std::move(info));
113  }
114  }
115 
116  for(const config& cfg : gamecfg.child_range("campaign")) {
117  config info;
118  info["id"] = cfg["id"];
119  info["name"] = cfg["name"];
120  info["allow_era_choice"] = cfg["allow_era_choice"];
121 
122  copy_keys(info, cfg, "era");
123  copy_keys(info, cfg, "modification", true);
124 
125  depinfo_.add_child("scenario", std::move(info));
126  }
127 }
128 
130 {
131  DBG_MP << "Saving current state";
132  prev_era_ = era_;
134  prev_mods_ = mods_;
135 }
136 
138 {
139  DBG_MP << "Restoring previous state";
140  era_ = prev_era_;
142  mods_ = prev_mods_;
143 }
144 
145 bool manager::exists(const elem& e) const
146 {
147  for(const config& cfg : depinfo_.child_range(e.type)) {
148  if(cfg["id"] == e.id) {
149  return true;
150  }
151  }
152 
153  return false;
154 }
155 
156 std::string manager::find_name_for(const elem& e) const
157 {
158  auto cfg = depinfo_.find_mandatory_child(e.type, "id", e.id);
159  return cfg["name"];
160 }
161 
162 std::vector<std::string> manager::get_required_not_installed(const elem& e) const
163 {
164  std::vector<std::string> result;
165 
166  std::vector<std::string> items = get_required(e);
167 
168  for(const std::string& str : items) {
169  if(!exists(elem(str, "modification"))) {
170  result.push_back(str);
171  }
172  }
173 
174  return result;
175 }
176 
177 std::vector<std::string> manager::get_required(const elem& e) const
178 {
179  std::vector<std::string> result;
180 
181  if(e.type == "modification") {
182  return result;
183  }
184 
185  config data = depinfo_.find_mandatory_child(e.type, "id", e.id);
186 
187  if(data.has_attribute("force_modification")) {
188  result = utils::split(data["force_modification"].str(), ',');
189  }
190 
191  return result;
192 }
193 
194 std::vector<std::string> manager::get_required_not_enabled(const elem& e) const
195 {
196  std::vector<std::string> required = get_required(e);
197  std::vector<std::string> result;
198 
199  for(std::string str : required) {
200  if(!utils::contains(mods_, str)) {
201  result.push_back(str);
202  }
203  }
204 
205  return result;
206 }
207 
208 std::vector<std::string> manager::get_conflicting_enabled(const elem& e) const
209 {
210  std::vector<std::string> result;
211 
212  for(const std::string& mod : mods_) {
213  if(does_conflict(elem(mod, "modification"), e)) {
214  result.push_back(mod);
215  }
216  }
217 
218  return result;
219 }
220 
221 bool manager::does_conflict(const elem& elem1, const elem& elem2, bool directonly) const
222 {
223  if(elem1 == elem2) {
224  return false;
225  }
226 
227  // We ignore nonexistent elements at this point, they will generate
228  // errors in change_era()/change_scenario() anyways.
229  if(!exists(elem1) || !exists(elem2)) {
230  return false;
231  }
232 
233  config data1 = depinfo_.find_mandatory_child(elem1.type, "id", elem1.id);
234  config data2 = depinfo_.find_mandatory_child(elem2.type, "id", elem2.id);
235 
236  // Whether we should skip the check entirely
237  if(data1.has_attribute("ignore_incompatible_" + elem2.type)) {
238  std::vector<std::string> ignored = utils::split(data1["ignore_incompatible_" + elem2.type]);
239 
240  if(utils::contains(ignored, elem2.id)) {
241  return false;
242  }
243  }
244 
245  if(data2.has_attribute("ignore_incompatible_" + elem1.type)) {
246  std::vector<std::string> ignored = utils::split(data2["ignore_incompatible_" + elem1.type]);
247 
248  if(utils::contains(ignored, elem1.id)) {
249  return false;
250  }
251  }
252 
253  if((elem1.type == "era" && data2["allow_era_choice"].to_bool(false)) ||(elem2.type == "era" && data1["allow_era_choice"].to_bool(false))) {
254  return false;
255  }
256 
257  bool result = false;
258 
259  // Checking for direct conflicts between elem1 and elem2
260  if(data1.has_attribute("allow_" + elem2.type)) {
261  std::vector<std::string> allowed = utils::split(data1["allow_" + elem2.type]);
262 
263  result = !utils::contains(allowed, elem2.id) && !does_require(elem1, elem2);
264  } else if(data1.has_attribute("disallow_" + elem2.type)) {
265  std::vector<std::string> disallowed = utils::split(data1["disallow_" + elem2.type]);
266 
267  result = utils::contains(disallowed, elem2.id);
268  }
269 
270  if(data2.has_attribute("allow_" + elem1.type)) {
271  std::vector<std::string> allowed = utils::split(data2["allow_" + elem1.type]);
272 
273  result = result || (!utils::contains(allowed, elem1.id) && !does_require(elem2, elem1));
274  } else if(data2.has_attribute("disallow_" + elem1.type)) {
275  std::vector<std::string> disallowed = utils::split(data2["disallow_" + elem1.type]);
276 
277  result = result || utils::contains(disallowed, elem1.id);
278  }
279 
280  if(result) {
281  return true;
282  }
283 
284  // Checking for indirect conflicts (i.e. conflicts between dependencies)
285  if(!directonly) {
286  std::vector<std::string> req1 = get_required(elem1), req2 = get_required(elem2);
287 
288  for(const std::string& s : req1) {
289  elem m(s, "modification");
290 
291  if(does_conflict(elem2, m, true)) {
292  return true;
293  }
294  }
295 
296  for(const std::string& s : req2) {
297  elem m(s, "modification");
298 
299  if(does_conflict(elem1, m, true)) {
300  return true;
301  }
302  }
303 
304  for(const std::string& id1 : req1) {
305  elem m1(id1, "modification");
306 
307  for(const std::string& id2 : req2) {
308  elem m2(id2, "modification");
309 
310  if(does_conflict(m1, m2)) {
311  return true;
312  }
313  }
314  }
315  }
316 
317  return false;
318 }
319 
320 bool manager::does_require(const elem& elem1, const elem& elem2) const
321 {
322  if(elem2.type != "modification") {
323  return false;
324  }
325 
326  config data = depinfo_.find_mandatory_child(elem1.type, "id", elem1.id);
327 
328  if(data.has_attribute("force_modification")) {
329  std::vector<std::string> required = utils::split(data["force_modification"]);
330 
331  return utils::contains(required, elem2.id);
332  }
333 
334  return false;
335 }
336 
337 void manager::try_era(const std::string& id, bool force)
338 {
339  save_state();
340 
341  if(force) {
342  era_ = id;
343  } else if(!change_era(id)) {
344  revert();
345  }
346 }
347 
348 void manager::try_scenario(const std::string& id, bool force)
349 {
350  save_state();
351 
352  if(force) {
353  scenario_ = id;
354  } else if(!change_scenario(id)) {
355  revert();
356  }
357 }
358 
359 void manager::try_modifications(const std::vector<std::string>& ids, bool force)
360 {
361  save_state();
362 
363  if(force) {
364  mods_ = ids;
365  } else if(!change_modifications(ids)) {
366  revert();
367  }
368 }
369 
370 void manager::try_modification_by_index(int index, bool activate, bool force)
371 {
372  std::string id = depinfo_.mandatory_child("modification", index)["id"];
373  std::vector<std::string> mods_copy = mods_;
374 
375  if(activate) {
376  if(std::find(mods_copy.begin(), mods_copy.end(), id) == mods_copy.end()) {
377  mods_copy.push_back(id);
378  }
379  } else {
380  std::vector<std::string>::iterator pos = std::find(mods_copy.begin(), mods_copy.end(), id);
381  if(pos != mods_copy.end()) {
382  mods_copy.erase(pos);
383  }
384  }
385 
386  try_modifications(mods_copy, force);
387 }
388 
389 void manager::try_era_by_index(int index, bool force)
390 {
391  try_era(depinfo_.mandatory_child("era", index)["id"], force);
392 }
393 
395 {
396  try_scenario(depinfo_.mandatory_child("scenario", index)["id"], force);
397 }
398 
400 {
401  int result = 0;
402  for(const config& i : depinfo_.child_range("era")) {
403  if(i["id"] == era_) {
404  return result;
405  }
406 
407  result++;
408  }
409 
410  return -1;
411 }
412 
414 {
415  int result = 0;
416 
417  for(const config& i : depinfo_.child_range("scenario")) {
418  if(i["id"] == scenario_) {
419  return result;
420  }
421 
422  result++;
423  }
424 
425  return -1;
426 }
427 
429 {
430  std::string id = depinfo_.mandatory_child("modification", index)["id"];
431  return std::find(mods_.begin(), mods_.end(), id) != mods_.end();
432 }
433 
434 bool manager::is_modification_active(const std::string id) const
435 {
436  return std::find(mods_.begin(), mods_.end(), id) != mods_.end();
437 }
438 
439 bool manager::enable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
440 {
441  std::vector<std::string> items;
442  for(const std::string& mod : mods) {
443  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
444  }
445 
446  return gui2::dialogs::depcheck_confirm_change::execute(true, items, requester);
447 }
448 
449 bool manager::disable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
450 {
451  std::vector<std::string> items;
452  for(const std::string& mod : mods) {
453  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
454  }
455 
456  return gui2::dialogs::depcheck_confirm_change::execute(false, items, requester);
457 }
458 
459 std::string manager::change_era_dialog(const std::vector<std::string>& eras)
460 {
461  std::vector<std::string> items;
462  for(const std::string& era : eras) {
463  items.push_back(depinfo_.find_mandatory_child("era", "id", era)["name"]);
464  }
465 
467 
468  if(dialog.show()) {
469  return eras[dialog.result()];
470  }
471 
472  return "";
473 }
474 
475 std::string manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
476 {
477  std::vector<std::string> items;
478  for(const std::string& scenario : scenarios) {
479  items.push_back(depinfo_.find_mandatory_child("scenario", "id", scenario)["name"]);
480  }
481 
483  if(dialog.show()) {
484  return scenarios[dialog.result()];
485  }
486 
487  return "";
488 }
489 
490 void manager::failure_dialog(const std::string& msg)
491 {
492  gui2::show_message(_("Failed to resolve dependencies"), msg, _("OK"));
493 }
494 
496 {
497  std::string type_str;
498 
499  switch(type) {
500  case ERA:
501  type_str = "era";
502  break;
503  case SCENARIO:
504  type_str = "scenario";
505  break;
506  case MODIFICATION:
507  type_str = "modification";
508  }
509 
510  depinfo_.add_child_at(type_str, data, index);
511 }
512 
513 bool manager::change_scenario(const std::string& id)
514 {
515  // Checking for missing dependencies
516  if(!get_required_not_installed(elem(id, "scenario")).empty()) {
517  std::string msg = _("Scenario can't be activated. Some dependencies are missing: ");
518 
519  msg += utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
520 
522  return false;
523  }
524 
525  scenario_ = id;
526 
527  elem scen = elem(id, "scenario");
528  std::string scen_name = find_name_for(scen);
529 
530  // Firstly, we check if we have to enable/disable any mods
531  std::vector<std::string> req = get_required_not_enabled(scen);
532  std::vector<std::string> con = get_conflicting_enabled(scen);
533 
534  if(!req.empty()) {
535  if(!enable_mods_dialog(req, scen_name)) {
536  return false;
537  }
538  }
539 
540  if(!con.empty()) {
541  if(!disable_mods_dialog(con, scen_name)) {
542  return false;
543  }
544  }
545 
546  std::vector<std::string> newmods = req;
547  for(const std::string& i : mods_) {
548  if(!utils::contains(con, i)) {
549  newmods.push_back(i);
550  }
551  }
552 
553  mods_ = newmods;
554 
555  // Now checking if the currently selected era conflicts the scenario
556  // and changing era if necessary
557  if(!does_conflict(scen, elem(era_, "era"))) {
558  return true;
559  }
560 
561  std::vector<std::string> compatible;
562  for(const config& i : depinfo_.child_range("era")) {
563  if(!does_conflict(scen, elem(i["id"], "era"))) {
564  compatible.push_back(i["id"]);
565  }
566  }
567 
568  if(!compatible.empty()) {
569  era_ = change_era_dialog(compatible);
570  } else {
571  failure_dialog(_("No compatible eras found."));
572  return false;
573  }
574 
575  if(era_.empty()) {
576  return false;
577  }
578 
579  return change_era(era_);
580 }
581 
582 bool manager::change_era(const std::string& id)
583 {
584  // Checking for missing dependencies
585  if(!get_required_not_installed(elem(id, "era")).empty()) {
586  std::string msg = _("Era can't be activated. Some dependencies are missing: ");
587 
588  msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
590  return false;
591  }
592 
593  era_ = id;
594 
595  elem era = elem(id, "era");
596  std::string era_name = find_name_for(era);
597 
598  std::vector<std::string> req = get_required_not_enabled(era);
599  std::vector<std::string> con = get_conflicting_enabled(era);
600 
601  // Firstly, we check if we have to enable/disable any mods
602  if(!req.empty()) {
603  if(!enable_mods_dialog(req, era_name)) {
604  return false;
605  }
606  }
607 
608  if(!con.empty()) {
609  if(!disable_mods_dialog(con, era_name)) {
610  return false;
611  }
612  }
613 
614  std::vector<std::string> newmods = req;
615  for(const std::string& i : mods_) {
616  if(!utils::contains(con, i)) {
617  newmods.push_back(i);
618  }
619  }
620 
621  mods_ = newmods;
622 
623  // Now checking if the currently selected scenario conflicts the era
624  // and changing scenario if necessary
625  if(!does_conflict(era, elem(scenario_, "scenario"))) {
626  return true;
627  }
628 
629  std::vector<std::string> compatible;
630  for(const config& i : depinfo_.child_range("scenario")) {
631  if(!does_conflict(era, elem(i["id"], "scenario"))) {
632  compatible.push_back(i["id"]);
633  }
634  }
635 
636  if(!compatible.empty()) {
637  scenario_ = change_scenario_dialog(compatible);
638  } else {
639  failure_dialog(_("No compatible scenarios found."));
640  return false;
641  }
642 
643  if(scenario_.empty()) {
644  return false;
645  }
646 
647  return change_scenario(scenario_);
648 }
649 
650 bool manager::change_modifications(const std::vector<std::string>& modifications)
651 {
652  // Checking if the selected combination of mods is valid at all
653  std::vector<std::string> filtered;
654  for(const std::string& i : modifications) {
655  bool ok = true;
656  elem ei(i, "modification");
657 
658  for(const std::string& j : filtered) {
659  ok = ok && !does_conflict(ei, elem(j, "modification"));
660  }
661 
662  if(ok) {
663  filtered.push_back(i);
664  }
665  }
666 
667  if(filtered.size() != modifications.size()) {
668  failure_dialog(_("Not all of the chosen modifications are compatible."
669  " Some of them will be disabled."));
670  }
671 
672  mods_ = filtered;
673 
674  // Checking if the currently selected era is compatible with the set
675  // modifications, and changing era if necessary
676  std::vector<std::string> compatible;
677  for(const config& c : depinfo_.child_range("era")) {
678  elem era(c["id"], "era");
679  bool ok = true;
680 
681  for(const std::string& s : mods_) {
682  ok = ok && !does_conflict(era, elem(s, "modification"));
683  }
684 
685  if(ok) {
686  compatible.push_back(era.id);
687  }
688  }
689 
690  if(!utils::contains(compatible, era_)) {
691  if(!compatible.empty()) {
692  era_ = change_era_dialog(compatible);
693  } else {
694  failure_dialog(_("No compatible eras found."));
695  return false;
696  }
697 
698  if(era_.empty()) {
699  return false;
700  }
701 
702  if(!change_era(era_)) {
703  return false;
704  }
705  } else {
706  if(!change_era(era_)) {
707  return false;
708  }
709  }
710 
711  compatible.clear();
712 
713  // Checking if the currently selected scenario is compatible with
714  // the set modifications, and changing scenario if necessary
715  for(const config& c : depinfo_.child_range("scenario")) {
716  elem scen(c["id"], "scenario");
717  bool ok = true;
718  for(const std::string& s : mods_) {
719  ok = ok && !does_conflict(scen, elem(s, "modification"));
720  }
721 
722  if(ok) {
723  compatible.push_back(scen.id);
724  }
725  }
726 
727  if(!utils::contains(compatible, scenario_)) {
728  if(!compatible.empty()) {
729  scenario_ = change_scenario_dialog(compatible);
730  } else {
731  failure_dialog(_("No compatible scenarios found."));
732  return false;
733  }
734 
735  if(scenario_.empty()) {
736  return false;
737  }
738 
739  return change_scenario(scenario_);
740  } else {
741  if(!change_scenario(scenario_)) {
742  return false;
743  }
744  }
745 
746  return true;
747 }
748 
749 } // namespace depcheck
750 
751 } // namespace ng
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
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:371
config & add_child_at(config_key_type key, const config &val, std::size_t index)
Definition: config.cpp:471
config & find_mandatory_child(config_key_type key, const std::string &name, const std::string &value)
Definition: config.cpp:817
bool has_attribute(config_key_type key) const
Definition: config.cpp:159
child_itors child_range(config_key_type key)
Definition: config.cpp:277
config & add_child(config_key_type key)
Definition: config.cpp:445
A class grating read only view to a vector of config objects, viewed as one config with all children ...
config_array_view child_range(config_key_type key) const
Offers a list of compatible items if a currently selected one is incompatible.
int result() const
Returns the selected item.
bool show(const unsigned auto_close_time=0)
Shows the window.
bool change_scenario(const std::string &id)
Attempts to change the selected scenario.
Definition: depcheck.cpp:513
void try_era_by_index(int index, bool force=false)
Tries to set the selected era.
Definition: depcheck.cpp:389
bool change_modifications(const std::vector< std::string > &modifications)
Attempts to change the selected modifications.
Definition: depcheck.cpp:650
void revert()
restores the lastly saved values of era_, scenarios_ and mods_
Definition: depcheck.cpp:137
void try_modifications(const std::vector< std::string > &ids, bool force=false)
Tries to set the enabled modifications.
Definition: depcheck.cpp:359
bool disable_mods_dialog(const std::vector< std::string > &mods, const std::string &requester=_("A component"))
Display a dialog requesting confirmation for disabling some modifications.
Definition: depcheck.cpp:449
bool exists(const elem &e) const
Decides whether a certain component is installed or not.
Definition: depcheck.cpp:145
void insert_element(component_type type, const config &data, int index=0)
Adds a new element to the manager's database.
Definition: depcheck.cpp:495
std::string change_era_dialog(const std::vector< std::string > &eras)
Display a dialog requesting the user to select a new era.
Definition: depcheck.cpp:459
void try_era(const std::string &id, bool force=false)
Tries to set the selected era.
Definition: depcheck.cpp:337
bool enable_mods_dialog(const std::vector< std::string > &mods, const std::string &requester=_("A component"))
Display a dialog requesting confirmation for enabling some modifications.
Definition: depcheck.cpp:439
bool does_conflict(const elem &elem1, const elem &elem2, bool directonly=false) const
Decides if two components are conflicting or not.
Definition: depcheck.cpp:221
void try_modification_by_index(int index, bool activate, bool force=false)
Tries to enable/disable a specific modification.
Definition: depcheck.cpp:370
config depinfo_
holds all required info about the components and their dependencies
Definition: depcheck.hpp:186
std::vector< std::string > get_required(const elem &e) const
Get the list of modifications required by a certain component.
Definition: depcheck.cpp:177
std::string prev_era_
used by save_state() and revert() to backup/restore era_
Definition: depcheck.hpp:198
std::vector< std::string > get_conflicting_enabled(const elem &e) const
Get the list of modifications which are conflicting a certain component and are currently enabled.
Definition: depcheck.cpp:208
std::string find_name_for(const elem &e) const
Look up the name of a given component.
Definition: depcheck.cpp:156
bool does_require(const elem &elem1, const elem &elem2) const
Decides whether e1 requires e2.
Definition: depcheck.cpp:320
std::vector< std::string > mods_
the ids of the currently selected modifications
Definition: depcheck.hpp:195
int get_era_index() const
Returns the selected era.
Definition: depcheck.cpp:399
std::string scenario_
the id of the currently selected scenario
Definition: depcheck.hpp:192
std::vector< std::string > get_required_not_installed(const elem &e) const
Get the list of modifications which are required by a certain component, but currently unavailable on...
Definition: depcheck.cpp:162
std::string change_scenario_dialog(const std::vector< std::string > &scenarios)
Display a dialog requesting the user to select a new scenario.
Definition: depcheck.cpp:475
bool is_modification_active(int index) const
Tells whether a certain mod is activated.
Definition: depcheck.cpp:428
std::string era_
the id of the currently selected era
Definition: depcheck.hpp:189
void try_scenario(const std::string &id, bool force=false)
Tries to set the selected scenario.
Definition: depcheck.cpp:348
void try_scenario_by_index(int index, bool force=false)
Tries to set the selected scenario.
Definition: depcheck.cpp:394
manager(const game_config_view &gamecfg, bool mp)
Definition: depcheck.cpp:61
void failure_dialog(const std::string &msg)
Shows an error message.
Definition: depcheck.cpp:490
bool change_era(const std::string &id)
Attempts to change the selected era.
Definition: depcheck.cpp:582
void save_state()
saves the current values of era_, scenarios_ and mods_
Definition: depcheck.cpp:129
std::string prev_scenario_
used by save_state() and revert() to backup/restore scenario_
Definition: depcheck.hpp:201
int get_scenario_index() const
Returns the selected scenario.
Definition: depcheck.cpp:413
std::vector< std::string > get_required_not_enabled(const elem &e) const
Get the list of modifications which are required by a certain component, but aren't currently enabled...
Definition: depcheck.cpp:194
std::vector< std::string > prev_mods_
used by save_state() and revert() to backup/restore mods_
Definition: depcheck.hpp:204
static lg::log_domain log_mp_create_depcheck("mp/create/depcheck")
#define DBG_MP
Definition: depcheck.cpp:32
std::size_t i
Definition: function.cpp:968
unsigned in
If equal to search_counter, the node is off the list.
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
Standard logging facilities (interface).
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:151
logger & info()
Definition: log.cpp:238
const std::vector< std::string > items
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:52
std::string era()
Definition: game.cpp:681
const std::vector< std::string > & modifications(bool mp)
Definition: game.cpp:711
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:84
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
std::string_view data
Definition: picture.cpp:199
represents a component (era, modification or scenario)
Definition: depcheck.hpp:170
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
mock_char c
static map_location::DIRECTION s
#define e