The Battle for Wesnoth  1.19.27+dev
depcheck.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2025
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_id(const std::string& id, bool activate, bool force)
371 {
372  std::vector<std::string> mods_copy = mods_;
373 
374  if(activate) {
375  if(!utils::contains(mods_copy, id) ) {
376  mods_copy.push_back(id);
377  }
378  } else {
379  std::vector<std::string>::iterator pos = std::find(mods_copy.begin(), mods_copy.end(), id);
380  if(pos != mods_copy.end()) {
381  mods_copy.erase(pos);
382  }
383  }
384 
385  try_modifications(mods_copy, force);
386 }
387 
388 void manager::try_era_by_index(int index, bool force)
389 {
390  try_era(depinfo_.mandatory_child("era", index)["id"], force);
391 }
392 
394 {
395  try_scenario(depinfo_.mandatory_child("scenario", index)["id"], force);
396 }
397 
399 {
400  return get_era_index(era_);
401 }
402 
403 int manager::get_era_index(const std::string& id) const
404 {
405  int result = 0;
406  for(const config& i : depinfo_.child_range("era")) {
407  if(i["id"] == id) {
408  return result;
409  }
410 
411  result++;
412  }
413 
414  return -1;
415 }
416 
418 {
419  int result = 0;
420 
421  for(const config& i : depinfo_.child_range("scenario")) {
422  if(i["id"] == scenario_) {
423  return result;
424  }
425 
426  result++;
427  }
428 
429  return -1;
430 }
431 
433 {
434  return utils::contains(mods_, depinfo_.mandatory_child("modification", index)["id"].str());
435 }
436 
437 bool manager::is_modification_active(const std::string& id) const
438 {
439  return utils::contains(mods_, id);
440 }
441 
442 bool manager::enable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
443 {
444  std::vector<std::string> items;
445  for(const std::string& mod : mods) {
446  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
447  }
448 
449  return gui2::dialogs::depcheck_confirm_change::execute(true, items, requester);
450 }
451 
452 bool manager::disable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
453 {
454  std::vector<std::string> items;
455  for(const std::string& mod : mods) {
456  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
457  }
458 
459  return gui2::dialogs::depcheck_confirm_change::execute(false, items, requester);
460 }
461 
462 std::string manager::change_era_dialog(const std::vector<std::string>& eras)
463 {
464  std::vector<std::string> items;
465  for(const std::string& era : eras) {
466  items.push_back(depinfo_.find_mandatory_child("era", "id", era)["name"]);
467  }
468 
470 
471  if(dialog.show()) {
472  return eras[dialog.result()];
473  }
474 
475  return "";
476 }
477 
478 std::string manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
479 {
480  std::vector<std::string> items;
481  for(const std::string& scenario : scenarios) {
482  items.push_back(depinfo_.find_mandatory_child("scenario", "id", scenario)["name"]);
483  }
484 
486  if(dialog.show()) {
487  return scenarios[dialog.result()];
488  }
489 
490  return "";
491 }
492 
493 void manager::failure_dialog(const std::string& msg)
494 {
495  gui2::show_message(_("Failed to resolve dependencies"), msg, _("OK"));
496 }
497 
499 {
500  std::string type_str;
501 
502  switch(type) {
503  case ERA:
504  type_str = "era";
505  break;
506  case SCENARIO:
507  type_str = "scenario";
508  break;
509  case MODIFICATION:
510  type_str = "modification";
511  }
512 
513  depinfo_.add_child_at(type_str, data, index);
514 }
515 
516 bool manager::change_scenario(const std::string& id)
517 {
518  // Checking for missing dependencies
519  if(!get_required_not_installed(elem(id, "scenario")).empty()) {
520  std::string msg = _("Scenario can’t be activated. Some dependencies are missing: ");
521 
522  msg += utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
523 
525  return false;
526  }
527 
528  scenario_ = id;
529 
530  elem scen = elem(id, "scenario");
531  std::string scen_name = find_name_for(scen);
532 
533  // Firstly, we check if we have to enable/disable any mods
534  std::vector<std::string> req = get_required_not_enabled(scen);
535  std::vector<std::string> con = get_conflicting_enabled(scen);
536 
537  if(!req.empty()) {
538  if(!enable_mods_dialog(req, scen_name)) {
539  return false;
540  }
541  }
542 
543  if(!con.empty()) {
544  if(!disable_mods_dialog(con, scen_name)) {
545  return false;
546  }
547  }
548 
549  std::vector<std::string> newmods = req;
550  for(const std::string& i : mods_) {
551  if(!utils::contains(con, i)) {
552  newmods.push_back(i);
553  }
554  }
555 
556  mods_ = newmods;
557 
558  // Now checking if the currently selected era conflicts the scenario
559  // and changing era if necessary
560  if(!does_conflict(scen, elem(era_, "era"))) {
561  return true;
562  }
563 
564  std::vector<std::string> compatible;
565  for(const config& i : depinfo_.child_range("era")) {
566  if(!does_conflict(scen, elem(i["id"], "era"))) {
567  compatible.push_back(i["id"]);
568  }
569  }
570 
571  if(!compatible.empty()) {
572  era_ = change_era_dialog(compatible);
573  } else {
574  failure_dialog(_("No compatible eras found."));
575  return false;
576  }
577 
578  if(era_.empty()) {
579  return false;
580  }
581 
582  return change_era(era_);
583 }
584 
585 bool manager::change_era(const std::string& id)
586 {
587  // Checking for missing dependencies
588  if(!get_required_not_installed(elem(id, "era")).empty()) {
589  std::string msg = _("Era can’t be activated. Some dependencies are missing: ");
590 
591  msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
593  return false;
594  }
595 
596  era_ = id;
597 
598  elem era = elem(id, "era");
599  std::string era_name = find_name_for(era);
600 
601  std::vector<std::string> req = get_required_not_enabled(era);
602  std::vector<std::string> con = get_conflicting_enabled(era);
603 
604  // Firstly, we check if we have to enable/disable any mods
605  if(!req.empty()) {
606  if(!enable_mods_dialog(req, era_name)) {
607  return false;
608  }
609  }
610 
611  if(!con.empty()) {
612  if(!disable_mods_dialog(con, era_name)) {
613  return false;
614  }
615  }
616 
617  std::vector<std::string> newmods = req;
618  for(const std::string& i : mods_) {
619  if(!utils::contains(con, i)) {
620  newmods.push_back(i);
621  }
622  }
623 
624  mods_ = newmods;
625 
626  // Now checking if the currently selected scenario conflicts the era
627  // and changing scenario if necessary
628  if(!does_conflict(era, elem(scenario_, "scenario"))) {
629  return true;
630  }
631 
632  std::vector<std::string> compatible;
633  for(const config& i : depinfo_.child_range("scenario")) {
634  if(!does_conflict(era, elem(i["id"], "scenario"))) {
635  compatible.push_back(i["id"]);
636  }
637  }
638 
639  if(!compatible.empty()) {
640  scenario_ = change_scenario_dialog(compatible);
641  } else {
642  failure_dialog(_("No compatible scenarios found."));
643  return false;
644  }
645 
646  if(scenario_.empty()) {
647  return false;
648  }
649 
650  return change_scenario(scenario_);
651 }
652 
653 bool manager::change_modifications(const std::vector<std::string>& modifications)
654 {
655  // Checking if the selected combination of mods is valid at all
656  std::vector<std::string> filtered;
657  for(const std::string& i : modifications) {
658  bool ok = true;
659  elem ei(i, "modification");
660 
661  for(const std::string& j : filtered) {
662  ok = ok && !does_conflict(ei, elem(j, "modification"));
663  }
664 
665  if(ok) {
666  filtered.push_back(i);
667  }
668  }
669 
670  if(filtered.size() != modifications.size()) {
671  failure_dialog(_("Not all of the chosen modifications are compatible."
672  " Some of them will be disabled."));
673  }
674 
675  mods_ = filtered;
676 
677  // Checking if the currently selected era is compatible with the set
678  // modifications, and changing era if necessary
679  std::vector<std::string> compatible;
680  for(const config& c : depinfo_.child_range("era")) {
681  elem era(c["id"], "era");
682  bool ok = true;
683 
684  for(const std::string& s : mods_) {
685  ok = ok && !does_conflict(era, elem(s, "modification"));
686  }
687 
688  if(ok) {
689  compatible.push_back(era.id);
690  }
691  }
692 
693  if(!utils::contains(compatible, era_)) {
694  if(!compatible.empty()) {
695  era_ = change_era_dialog(compatible);
696  } else {
697  failure_dialog(_("No compatible eras found."));
698  return false;
699  }
700 
701  if(era_.empty()) {
702  return false;
703  }
704 
705  if(!change_era(era_)) {
706  return false;
707  }
708  } else {
709  if(!change_era(era_)) {
710  return false;
711  }
712  }
713 
714  compatible.clear();
715 
716  // Checking if the currently selected scenario is compatible with
717  // the set modifications, and changing scenario if necessary
718  for(const config& c : depinfo_.child_range("scenario")) {
719  elem scen(c["id"], "scenario");
720  bool ok = true;
721  for(const std::string& s : mods_) {
722  ok = ok && !does_conflict(scen, elem(s, "modification"));
723  }
724 
725  if(ok) {
726  compatible.push_back(scen.id);
727  }
728  }
729 
730  if(!utils::contains(compatible, scenario_)) {
731  if(!compatible.empty()) {
732  scenario_ = change_scenario_dialog(compatible);
733  } else {
734  failure_dialog(_("No compatible scenarios found."));
735  return false;
736  }
737 
738  if(scenario_.empty()) {
739  return false;
740  }
741 
742  return change_scenario(scenario_);
743  } else {
744  if(!change_scenario(scenario_)) {
745  return false;
746  }
747  }
748 
749  return true;
750 }
751 
752 } // namespace depcheck
753 
754 } // namespace ng
unsigned in
If equal to search_counter, the node is off the list.
Definition: astarsearch.cpp:70
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
config & add_child(std::string_view key)
Definition: config.cpp:436
config & find_mandatory_child(std::string_view key, const std::string &name, const std::string &value)
Definition: config.cpp:784
child_itors child_range(std::string_view key)
Definition: config.cpp:268
bool has_attribute(std::string_view key) const
Definition: config.cpp:157
config & add_child_at(std::string_view key, const config &val, std::size_t index)
Definition: config.cpp:465
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:362
A class grating read only view to a vector of config objects, viewed as one config with all children ...
config_array_view child_range(std::string_view key) const
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:516
void try_era_by_index(int index, bool force=false)
Tries to set the selected era.
Definition: depcheck.cpp:388
bool change_modifications(const std::vector< std::string > &modifications)
Attempts to change the selected modifications.
Definition: depcheck.cpp:653
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:452
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:498
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:462
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:442
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
config depinfo_
holds all required info about the components and their dependencies
Definition: depcheck.hpp:187
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:199
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:196
int get_era_index() const
Returns the selected era.
Definition: depcheck.cpp:398
std::string scenario_
the id of the currently selected scenario
Definition: depcheck.hpp:193
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:478
bool is_modification_active(int index) const
Tells whether a certain mod is activated.
Definition: depcheck.cpp:432
std::string era_
the id of the currently selected era
Definition: depcheck.hpp:190
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:393
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:493
bool change_era(const std::string &id)
Attempts to change the selected era.
Definition: depcheck.cpp:585
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:202
int get_scenario_index() const
Returns the selected scenario.
Definition: depcheck.cpp:417
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
void try_modification_by_id(const std::string &id, bool activate, bool force=false)
Tries to enable/disable a specific modification.
Definition: depcheck.cpp:370
std::vector< std::string > prev_mods_
used by save_state() and revert() to backup/restore mods_
Definition: depcheck.hpp:205
static lg::log_domain log_mp_create_depcheck("mp/create/depcheck")
#define DBG_MP
Definition: depcheck.cpp:32
const config * cfg
std::size_t i
Definition: function.cpp:1031
static std::string _(const char *str)
Definition: gettext.hpp:100
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:199
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:148
logger & info()
Definition: log.cpp:351
Main entry points of multiplayer mode.
Definition: lobby_data.cpp:49
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition: general.hpp:88
std::string join(const Range &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)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:142
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:109
std::string_view data
Definition: picture.cpp:188
represents a component (era, modification or scenario)
Definition: depcheck.hpp:171
static constexpr utils::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