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