The Battle for Wesnoth  1.19.10+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(std::find(mods_copy.begin(), mods_copy.end(), id) == mods_copy.end()) {
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  std::string id = depinfo_.mandatory_child("modification", index)["id"];
444  return std::find(mods_.begin(), mods_.end(), id) != mods_.end();
445 }
446 
447 bool manager::is_modification_active(const std::string& id) const
448 {
449  return std::find(mods_.begin(), mods_.end(), id) != mods_.end();
450 }
451 
452 bool manager::enable_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(true, items, requester);
460 }
461 
462 bool manager::disable_mods_dialog(const std::vector<std::string>& mods, const std::string& requester)
463 {
464  std::vector<std::string> items;
465  for(const std::string& mod : mods) {
466  items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
467  }
468 
469  return gui2::dialogs::depcheck_confirm_change::execute(false, items, requester);
470 }
471 
472 std::string manager::change_era_dialog(const std::vector<std::string>& eras)
473 {
474  std::vector<std::string> items;
475  for(const std::string& era : eras) {
476  items.push_back(depinfo_.find_mandatory_child("era", "id", era)["name"]);
477  }
478 
480 
481  if(dialog.show()) {
482  return eras[dialog.result()];
483  }
484 
485  return "";
486 }
487 
488 std::string manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
489 {
490  std::vector<std::string> items;
491  for(const std::string& scenario : scenarios) {
492  items.push_back(depinfo_.find_mandatory_child("scenario", "id", scenario)["name"]);
493  }
494 
496  if(dialog.show()) {
497  return scenarios[dialog.result()];
498  }
499 
500  return "";
501 }
502 
503 void manager::failure_dialog(const std::string& msg)
504 {
505  gui2::show_message(_("Failed to resolve dependencies"), msg, _("OK"));
506 }
507 
509 {
510  std::string type_str;
511 
512  switch(type) {
513  case ERA:
514  type_str = "era";
515  break;
516  case SCENARIO:
517  type_str = "scenario";
518  break;
519  case MODIFICATION:
520  type_str = "modification";
521  }
522 
523  depinfo_.add_child_at(type_str, data, index);
524 }
525 
526 bool manager::change_scenario(const std::string& id)
527 {
528  // Checking for missing dependencies
529  if(!get_required_not_installed(elem(id, "scenario")).empty()) {
530  std::string msg = _("Scenario can’t be activated. Some dependencies are missing: ");
531 
532  msg += utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
533 
535  return false;
536  }
537 
538  scenario_ = id;
539 
540  elem scen = elem(id, "scenario");
541  std::string scen_name = find_name_for(scen);
542 
543  // Firstly, we check if we have to enable/disable any mods
544  std::vector<std::string> req = get_required_not_enabled(scen);
545  std::vector<std::string> con = get_conflicting_enabled(scen);
546 
547  if(!req.empty()) {
548  if(!enable_mods_dialog(req, scen_name)) {
549  return false;
550  }
551  }
552 
553  if(!con.empty()) {
554  if(!disable_mods_dialog(con, scen_name)) {
555  return false;
556  }
557  }
558 
559  std::vector<std::string> newmods = req;
560  for(const std::string& i : mods_) {
561  if(!utils::contains(con, i)) {
562  newmods.push_back(i);
563  }
564  }
565 
566  mods_ = newmods;
567 
568  // Now checking if the currently selected era conflicts the scenario
569  // and changing era if necessary
570  if(!does_conflict(scen, elem(era_, "era"))) {
571  return true;
572  }
573 
574  std::vector<std::string> compatible;
575  for(const config& i : depinfo_.child_range("era")) {
576  if(!does_conflict(scen, elem(i["id"], "era"))) {
577  compatible.push_back(i["id"]);
578  }
579  }
580 
581  if(!compatible.empty()) {
582  era_ = change_era_dialog(compatible);
583  } else {
584  failure_dialog(_("No compatible eras found."));
585  return false;
586  }
587 
588  if(era_.empty()) {
589  return false;
590  }
591 
592  return change_era(era_);
593 }
594 
595 bool manager::change_era(const std::string& id)
596 {
597  // Checking for missing dependencies
598  if(!get_required_not_installed(elem(id, "era")).empty()) {
599  std::string msg = _("Era can’t be activated. Some dependencies are missing: ");
600 
601  msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
603  return false;
604  }
605 
606  era_ = id;
607 
608  elem era = elem(id, "era");
609  std::string era_name = find_name_for(era);
610 
611  std::vector<std::string> req = get_required_not_enabled(era);
612  std::vector<std::string> con = get_conflicting_enabled(era);
613 
614  // Firstly, we check if we have to enable/disable any mods
615  if(!req.empty()) {
616  if(!enable_mods_dialog(req, era_name)) {
617  return false;
618  }
619  }
620 
621  if(!con.empty()) {
622  if(!disable_mods_dialog(con, era_name)) {
623  return false;
624  }
625  }
626 
627  std::vector<std::string> newmods = req;
628  for(const std::string& i : mods_) {
629  if(!utils::contains(con, i)) {
630  newmods.push_back(i);
631  }
632  }
633 
634  mods_ = newmods;
635 
636  // Now checking if the currently selected scenario conflicts the era
637  // and changing scenario if necessary
638  if(!does_conflict(era, elem(scenario_, "scenario"))) {
639  return true;
640  }
641 
642  std::vector<std::string> compatible;
643  for(const config& i : depinfo_.child_range("scenario")) {
644  if(!does_conflict(era, elem(i["id"], "scenario"))) {
645  compatible.push_back(i["id"]);
646  }
647  }
648 
649  if(!compatible.empty()) {
650  scenario_ = change_scenario_dialog(compatible);
651  } else {
652  failure_dialog(_("No compatible scenarios found."));
653  return false;
654  }
655 
656  if(scenario_.empty()) {
657  return false;
658  }
659 
660  return change_scenario(scenario_);
661 }
662 
663 bool manager::change_modifications(const std::vector<std::string>& modifications)
664 {
665  // Checking if the selected combination of mods is valid at all
666  std::vector<std::string> filtered;
667  for(const std::string& i : modifications) {
668  bool ok = true;
669  elem ei(i, "modification");
670 
671  for(const std::string& j : filtered) {
672  ok = ok && !does_conflict(ei, elem(j, "modification"));
673  }
674 
675  if(ok) {
676  filtered.push_back(i);
677  }
678  }
679 
680  if(filtered.size() != modifications.size()) {
681  failure_dialog(_("Not all of the chosen modifications are compatible."
682  " Some of them will be disabled."));
683  }
684 
685  mods_ = filtered;
686 
687  // Checking if the currently selected era is compatible with the set
688  // modifications, and changing era if necessary
689  std::vector<std::string> compatible;
690  for(const config& c : depinfo_.child_range("era")) {
691  elem era(c["id"], "era");
692  bool ok = true;
693 
694  for(const std::string& s : mods_) {
695  ok = ok && !does_conflict(era, elem(s, "modification"));
696  }
697 
698  if(ok) {
699  compatible.push_back(era.id);
700  }
701  }
702 
703  if(!utils::contains(compatible, era_)) {
704  if(!compatible.empty()) {
705  era_ = change_era_dialog(compatible);
706  } else {
707  failure_dialog(_("No compatible eras found."));
708  return false;
709  }
710 
711  if(era_.empty()) {
712  return false;
713  }
714 
715  if(!change_era(era_)) {
716  return false;
717  }
718  } else {
719  if(!change_era(era_)) {
720  return false;
721  }
722  }
723 
724  compatible.clear();
725 
726  // Checking if the currently selected scenario is compatible with
727  // the set modifications, and changing scenario if necessary
728  for(const config& c : depinfo_.child_range("scenario")) {
729  elem scen(c["id"], "scenario");
730  bool ok = true;
731  for(const std::string& s : mods_) {
732  ok = ok && !does_conflict(scen, elem(s, "modification"));
733  }
734 
735  if(ok) {
736  compatible.push_back(scen.id);
737  }
738  }
739 
740  if(!utils::contains(compatible, scenario_)) {
741  if(!compatible.empty()) {
742  scenario_ = change_scenario_dialog(compatible);
743  } else {
744  failure_dialog(_("No compatible scenarios found."));
745  return false;
746  }
747 
748  if(scenario_.empty()) {
749  return false;
750  }
751 
752  return change_scenario(scenario_);
753  } else {
754  if(!change_scenario(scenario_)) {
755  return false;
756  }
757  }
758 
759  return true;
760 }
761 
762 } // namespace depcheck
763 
764 } // namespace ng
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:806
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:526
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:663
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:462
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:508
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:472
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:452
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:488
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:503
bool change_era(const std::string &id)
Attempts to change the selected era.
Definition: depcheck.cpp:595
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
std::size_t i
Definition: function.cpp:1030
unsigned in
If equal to search_counter, the node is off the list.
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:318
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:86
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:140
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:178
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