The Battle for Wesnoth  1.19.0+dev
game_classification.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
3  by David White <dave@whitevine.net>
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 
16 #include "game_classification.hpp"
17 
18 #include "config.hpp"
19 #include "log.hpp"
22 #include "game_version.hpp"
23 #include "game_config_manager.hpp"
24 
25 #include <list>
26 
27 static lg::log_domain log_engine("engine");
28 #define ERR_NG LOG_STREAM(err, log_engine)
29 #define WRN_NG LOG_STREAM(warn, log_engine)
30 #define LOG_NG LOG_STREAM(info, log_engine)
31 #define DBG_NG LOG_STREAM(debug, log_engine)
32 
33 /** The default difficulty setting for campaigns. */
34 const std::string DEFAULT_DIFFICULTY("NORMAL");
35 
37  : label(cfg["label"])
38  , version(cfg["version"])
39  , type(campaign_type::get_enum(cfg["campaign_type"].str()).value_or(campaign_type::type::scenario))
40  , campaign_define(cfg["campaign_define"])
41  , campaign_xtra_defines(utils::split(cfg["campaign_extra_defines"]))
42  , scenario_define(cfg["scenario_define"])
43  , era_define(cfg["era_define"])
44  , mod_defines(utils::split(cfg["mod_defines"]))
45  , active_mods(utils::split(cfg["active_mods"]))
46  , era_id(cfg["era_id"])
47  , campaign(cfg["campaign"])
48  , campaign_name(cfg["campaign_name"])
49  , abbrev(cfg["abbrev"])
50  , end_credits(cfg["end_credits"].to_bool(true))
51  , end_text(cfg["end_text"])
52  , end_text_duration(std::clamp<unsigned>(cfg["end_text_duration"].to_unsigned(0), 0, 5000))
53  , difficulty(cfg["difficulty"].empty() ? DEFAULT_DIFFICULTY : cfg["difficulty"].str())
54  , random_mode(cfg["random_mode"])
55  , oos_debug(cfg["oos_debug"].to_bool(false))
56 {
57 }
58 
60 {
61  config cfg;
62  cfg["label"] = label;
63  cfg["version"] = game_config::wesnoth_version.str();
64  cfg["campaign_type"] = campaign_type::get_string(type);
65  cfg["campaign_define"] = campaign_define;
66  cfg["campaign_extra_defines"] = utils::join(campaign_xtra_defines);
67  cfg["scenario_define"] = scenario_define;
68  cfg["era_define"] = era_define;
69  cfg["mod_defines"] = utils::join(mod_defines);
70  cfg["active_mods"] = utils::join(active_mods);
71  cfg["era_id"] = era_id;
72  cfg["campaign"] = campaign;
73  cfg["campaign_name"] = campaign_name;
74  cfg["abbrev"] = abbrev;
75  cfg["end_credits"] = end_credits;
76  cfg["end_text"] = end_text;
77  cfg["end_text_duration"] = std::to_string(end_text_duration);
78  cfg["difficulty"] = difficulty;
79  cfg["random_mode"] = random_mode;
80  cfg["oos_debug"] = oos_debug;
81  cfg["core"] = prefs::get().core_id();
82 
83  return cfg;
84 }
85 
87 {
88  if(is_multiplayer()) {
89  return campaign.empty() ? campaign_type::multiplayer : campaign_type::scenario;
90  }
91 
92  if(is_tutorial()) {
93  return campaign_type::scenario;
94  }
95 
97 }
98 
99 namespace
100 {
101 // helper objects for saved_game::expand_mp_events()
102 struct modevents_entry
103 {
104  modevents_entry(const std::string& _type, const std::string& _id)
105  : type(_type)
106  , id(_id)
107  {
108  }
109 
110  std::string type;
111  std::string id;
112 };
113 }
114 
115 std::set<std::string> game_classification::active_addons(const std::string& scenario_id) const
116 {
117  //FIXME: this doesn't include mods from the current scenario.
118  std::list<modevents_entry> mods;
119  std::set<std::string> loaded_resources;
120  std::set<std::string> res;
121 
122  for(const auto& mod : active_mods) {
123  mods.emplace_back("modification", mod);
124  }
125 
126  // We don't want the error message below if there is no era (= if this is a sp game).
127  if(!era_id.empty()) {
128  mods.emplace_back(get_tagname(), scenario_id);
129  }
130 
131  if(!era_id.empty()) {
132  mods.emplace_back("era", era_id);
133  }
134 
135  if(!campaign.empty()) {
136  mods.emplace_back("campaign", campaign);
137  }
138  while(!mods.empty()) {
139 
140  const modevents_entry& current = mods.front();
141  if(current.type == "resource") {
142  if(!loaded_resources.insert(current.id).second) {
143  mods.pop_front();
144  continue;
145  }
146  }
147  if(auto cfg = game_config_manager::get()->game_config().find_child(current.type, "id", current.id)) {
148  if(!cfg["addon_id"].empty()) {
149  res.insert(cfg["addon_id"]);
150  }
151  for (const config& load_res : cfg->child_range("load_resource")) {
152  mods.emplace_back("resource", load_res["id"].str());
153  }
154  } else {
155  ERR_NG << "Unable to find config for content " << current.id << " of type " << current.type;
156  }
157  mods.pop_front( );
158  }
159 
160  DBG_NG << "Active content for game set to:";
161  for(const std::string& mod : res) {
162  DBG_NG << mod;
163  }
164 
165  return res;
166 }
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
child_itors child_range(config_key_type key)
Definition: config.cpp:273
std::vector< std::string > campaign_xtra_defines
more customization of data
std::vector< std::string > mod_defines
If there are defines the modifications use to customize data.
std::set< std::string > active_addons(const std::string &scenario_id) const
std::string scenario_define
If there is a define the scenario uses to customize data.
std::string difficulty
The difficulty level the game is being played on.
std::string era_define
If there is a define the era uses to customize data.
game_classification()=default
std::vector< std::string > active_mods
campaign_type::type type
bool end_credits
whether to show the standard credits at the end
std::string label
Name of the game (e.g.
unsigned int end_text_duration
for how long the end-of-campaign text is shown
std::string campaign_define
If there is a define the campaign uses to customize data.
std::string get_tagname() const
std::string campaign
The id of the campaign being played.
std::string abbrev
the campaign abbreviation
std::string end_text
end-of-campaign text
std::string campaign_name
The name of the campaign being played.
static game_config_manager * get()
static prefs & get()
std::string core_id()
std::string str() const
Serializes the version number into string form.
const std::string DEFAULT_DIFFICULTY("NORMAL")
The default difficulty setting for campaigns.
static lg::log_domain log_engine("engine")
#define ERR_NG
#define DBG_NG
Interfaces for manipulating version numbers of engine, add-ons, etc.
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:207
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:205
Standard logging facilities (interface).
Game configuration data as global variables.
Definition: build_info.cpp:61
const version_info wesnoth_version(VERSION)
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)
The base template for associating string values with enum values.
Definition: enum_base.hpp:33
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46