The Battle for Wesnoth  1.19.14+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  int result = 0;
401  for(const config& i : depinfo_.child_range("era")) {
402  if(i["id"] == era_) {
403  return result;
404  }
405 
406  result++;
407  }
408 
409  return -1;
410 }
411 
412 int manager::get_era_index(const std::string& id) const
413 {
414  int result = 0;
415  for(const config& i : depinfo_.child_range("era")) {
416  if(i["id"] == id) {
417  return result;
418  }
419 
420  result++;
421  }
422 
423  return -1;
424 }
425 
427 {
428  int result = 0;
429 
430  for(const config& i : depinfo_.child_range("scenario")) {
431  if(i["id"] == scenario_) {
432  return result;
433  }
434 
435  result++;
436  }
437 
438  return -1;
439 }
440 
442 {
443  return utils::contains(mods_, depinfo_.mandatory_child("modification", index)["id"]);
444 }
445 
446 bool manager::is_modification_active(const std::string& id) const
447 {
448  return utils::contains(mods_, id);
449 }
450 
451 bool manager::enable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
452 {
453  std::vector<std::string> items;
454  for(const std::string& mod : mods) {
455  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
456  }
457 
458  return gui2::dialogs::depcheck_confirm_change::execute(true, items, requester);
459 }
460 
461 bool manager::disable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
462 {
463  std::vector<std::string> items;
464  for(const std::string& mod : mods) {
465  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
466  }
467 
468  return gui2::dialogs::depcheck_confirm_change::execute(false, items, requester);
469 }
470 
471 std::string manager::change_era_dialog(const std::vector<std::string>& eras)
472 {
473  std::vector<std::string> items;
474  for(const std::string& era : eras) {
475  items.push_back(depinfo_.find_mandatory_child("era", "id", era)["name"]);
476  }
477 
479 
480  if(dialog.show()) {
481  return eras[dialog.result()];
482  }
483 
484  return "";
485 }
486 
487 std::string manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
488 {
489  std::vector<std::string> items;
490  for(const std::string& scenario : scenarios) {
491  items.push_back(depinfo_.find_mandatory_child("scenario", "id", scenario)["name"]);
492  }
493 
495  if(dialog.show()) {
496  return scenarios[dialog.result()];
497  }
498 
499  return "";
500 }
501 
502 void manager::failure_dialog(const std::string& msg)
503 {
504  gui2::show_message(_("Failed to resolve dependencies"), msg, _("OK"));
505 }
506 
508 {
509  std::string type_str;
510 
511  switch(type) {
512  case ERA:
513  type_str = "era";
514  break;
515  case SCENARIO:
516  type_str = "scenario";
517  break;
518  case MODIFICATION:
519  type_str = "modification";
520  }
521 
522  depinfo_.add_child_at(type_str, data, index);
523 }
524 
525 bool manager::change_scenario(const std::string& id)
526 {
527  // Checking for missing dependencies
528  if(!get_required_not_installed(elem(id, "scenario")).empty()) {
529  std::string msg = _("Scenario can’t be activated. Some dependencies are missing: ");
530 
531  msg += utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
532 
534  return false;
535  }
536 
537  scenario_ = id;
538 
539  elem scen = elem(id, "scenario");
540  std::string scen_name = find_name_for(scen);
541 
542  // Firstly, we check if we have to enable/disable any mods
543  std::vector<std::string> req = get_required_not_enabled(scen);
544  std::vector<std::string> con = get_conflicting_enabled(scen);
545 
546  if(!req.empty()) {
547  if(!enable_mods_dialog(req, scen_name)) {
548  return false;
549  }
550  }
551 
552  if(!con.empty()) {
553  if(!disable_mods_dialog(con, scen_name)) {
554  return false;
555  }
556  }
557 
558  std::vector<std::string> newmods = req;
559  for(const std::string& i : mods_) {
560  if(!utils::contains(con, i)) {
561  newmods.push_back(i);
562  }
563  }
564 
565  mods_ = newmods;
566 
567  // Now checking if the currently selected era conflicts the scenario
568  // and changing era if necessary
569  if(!does_conflict(scen, elem(era_, "era"))) {
570  return true;
571  }
572 
573  std::vector<std::string> compatible;
574  for(const config& i : depinfo_.child_range("era")) {
575  if(!does_conflict(scen, elem(i["id"], "era"))) {
576  compatible.push_back(i["id"]);
577  }
578  }
579 
580  if(!compatible.empty()) {
581  era_ = change_era_dialog(compatible);
582  } else {
583  failure_dialog(_("No compatible eras found."));
584  return false;
585  }
586 
587  if(era_.empty()) {
588  return false;
589  }
590 
591  return change_era(era_);
592 }
593 
594 bool manager::change_era(const std::string& id)
595 {
596  // Checking for missing dependencies
597  if(!get_required_not_installed(elem(id, "era")).empty()) {
598  std::string msg = _("Era can’t be activated. Some dependencies are missing: ");
599 
600  msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
602  return false;
603  }
604 
605  era_ = id;
606 
607  elem era = elem(id, "era");
608  std::string era_name = find_name_for(era);
609 
610  std::vector<std::string> req = get_required_not_enabled(era);
611  std::vector<std::string> con = get_conflicting_enabled(era);
612 
613  // Firstly, we check if we have to enable/disable any mods
614  if(!req.empty()) {
615  if(!enable_mods_dialog(req, era_name)) {
616  return false;
617  }
618  }
619 
620  if(!con.empty()) {
621  if(!disable_mods_dialog(con, era_name)) {
622  return false;
623  }
624  }
625 
626  std::vector<std::string> newmods = req;
627  for(const std::string& i : mods_) {
628  if(!utils::contains(con, i)) {
629  newmods.push_back(i);
630  }
631  }
632 
633  mods_ = newmods;
634 
635  // Now checking if the currently selected scenario conflicts the era
636  // and changing scenario if necessary
637  if(!does_conflict(era, elem(scenario_, "scenario"))) {
638  return true;
639  }
640 
641  std::vector<std::string> compatible;
642  for(const config& i : depinfo_.child_range("scenario")) {
643  if(!does_conflict(era, elem(i["id"], "scenario"))) {
644  compatible.push_back(i["id"]);
645  }
646  }
647 
648  if(!compatible.empty()) {
649  scenario_ = change_scenario_dialog(compatible);
650  } else {
651  failure_dialog(_("No compatible scenarios found."));
652  return false;
653  }
654 
655  if(scenario_.empty()) {
656  return false;
657  }
658 
659  return change_scenario(scenario_);
660 }
661 
662 bool manager::change_modifications(const std::vector<std::string>& modifications)
663 {
664  // Checking if the selected combination of mods is valid at all
665  std::vector<std::string> filtered;
666  for(const std::string& i : modifications) {
667  bool ok = true;
668  elem ei(i, "modification");
669 
670  for(const std::string& j : filtered) {
671  ok = ok && !does_conflict(ei, elem(j, "modification"));
672  }
673 
674  if(ok) {
675  filtered.push_back(i);
676  }
677  }
678 
679  if(filtered.size() != modifications.size()) {
680  failure_dialog(_("Not all of the chosen modifications are compatible."
681  " Some of them will be disabled."));
682  }
683 
684  mods_ = filtered;
685 
686  // Checking if the currently selected era is compatible with the set
687  // modifications, and changing era if necessary
688  std::vector<std::string> compatible;
689  for(const config& c : depinfo_.child_range("era")) {
690  elem era(c["id"], "era");
691  bool ok = true;
692 
693  for(const std::string& s : mods_) {
694  ok = ok && !does_conflict(era, elem(s, "modification"));
695  }
696 
697  if(ok) {
698  compatible.push_back(era.id);
699  }
700  }
701 
702  if(!utils::contains(compatible, era_)) {
703  if(!compatible.empty()) {
704  era_ = change_era_dialog(compatible);
705  } else {
706  failure_dialog(_("No compatible eras found."));
707  return false;
708  }
709 
710  if(era_.empty()) {
711  return false;
712  }
713 
714  if(!change_era(era_)) {
715  return false;
716  }
717  } else {
718  if(!change_era(era_)) {
719  return false;
720  }
721  }
722 
723  compatible.clear();
724 
725  // Checking if the currently selected scenario is compatible with
726  // the set modifications, and changing scenario if necessary
727  for(const config& c : depinfo_.child_range("scenario")) {
728  elem scen(c["id"], "scenario");
729  bool ok = true;
730  for(const std::string& s : mods_) {
731  ok = ok && !does_conflict(scen, elem(s, "modification"));
732  }
733 
734  if(ok) {
735  compatible.push_back(scen.id);
736  }
737  }
738 
739  if(!utils::contains(compatible, scenario_)) {
740  if(!compatible.empty()) {
741  scenario_ = change_scenario_dialog(compatible);
742  } else {
743  failure_dialog(_("No compatible scenarios found."));
744  return false;
745  }
746 
747  if(scenario_.empty()) {
748  return false;
749  }
750 
751  return change_scenario(scenario_);
752  } else {
753  if(!change_scenario(scenario_)) {
754  return false;
755  }
756  }
757 
758  return true;
759 }
760 
761 } // namespace depcheck
762 
763 } // 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:158
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:362
config & add_child_at(config_key_type key, const config &val, std::size_t index)
Definition: config.cpp:465
config & find_mandatory_child(config_key_type key, const std::string &name, const std::string &value)
Definition: config.cpp:800
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
child_itors child_range(config_key_type key)
Definition: config.cpp:268
config & add_child(config_key_type key)
Definition: config.cpp:436
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
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:525
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:662
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:461
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:507
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:471
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:451
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:487
bool is_modification_active(int index) const
Tells whether a certain mod is activated.
Definition: depcheck.cpp:441
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:502
bool change_era(const std::string &id)
Attempts to change the selected era.
Definition: depcheck.cpp:594
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:426
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:1032
static std::string _(const char *str)
Definition: gettext.hpp:97
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:87
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)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:141
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