The Battle for Wesnoth  1.17.12+dev
achievements.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2022
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 "achievements.hpp"
17 
18 #include "filesystem.hpp"
19 #include "game_config.hpp"
20 #include "log.hpp"
21 #include "preferences/general.hpp"
22 #include "serialization/parser.hpp"
24 
25 static lg::log_domain log_config("config");
26 #define ERR_CONFIG LOG_STREAM(err, log_config)
27 
29  : achievement_list_()
30 {
31  reload();
32 }
33 
34 /**
35  * Reads the mainline achievements.cfg and then all the achievements of each installed add-on.
36  *
37  * This is intentionally handled separately from other WML loading so that:
38  * a) All achievements and their status are able to be displayed on the main menu right after Wesnoth starts and regardless of which add-ons are active.
39  * b) Add-ons can add additional achievements to other content, whether UMC or mainline. For example, a modification that adds more achievements for mainline campaigns.
40  *
41  * NOTE: These are *not* in any way related to Steam achievements!
42  */
44 {
45  achievement_list_.clear();
46  // mainline
47  try {
48  config cfg = read_achievements_file(game_config::path + "/data/achievements.cfg");
49  process_achievements_file(cfg, "Mainline");
50  } catch(const game::error& e) {
51  ERR_CONFIG << "Error processing mainline achievements, ignoring: " << e.what();
52  }
53 
54  // add-ons
55  std::vector<std::string> dirs;
57  for(const std::string& dir : dirs) {
58  try {
59  config cfg = read_achievements_file(filesystem::get_addons_dir() + "/" + dir + "/achievements.cfg");
60  process_achievements_file(cfg, dir);
61  } catch(const game::error& e) {
62  ERR_CONFIG << "Error processing add-on " << dir << " achievements, ignoring: " << e.what();
63  }
64  }
65 }
66 
67 /**
68  * Reads an achievements.cfg file into a config.
69  *
70  * @param path The path to the achievements.cfg file.
71  * @return The config containing all the achievements.
72  */
74 {
75  config cfg;
76  if(filesystem::file_exists(path)) {
78  read(cfg, *stream);
79  }
80  return cfg;
81 }
82 
83 /**
84  * Processes a config object to add new achievements to @a achievement_list_.
85  *
86  * @param cfg The config containing additional achievements.
87  * @param content_source The source of the additional achievements - either mainline or an add-on.
88  */
89 void achievements::process_achievements_file(const config& cfg, const std::string& content_source)
90 {
91  for(const config& achgrp : cfg.child_range("achievement_group")) {
92  if(achgrp["content_for"].str().empty()) {
93  ERR_CONFIG << content_source + " achievement_group missing content_for attribute:\n" << achgrp.debug();
94  continue;
95  }
96  achievement_list_.emplace_back(achgrp);
97  }
98 }
99 
101  : display_name_(cfg["display_name"].t_str())
102  , content_for_(cfg["content_for"].str())
103  , achievements_()
104 {
105  for(const config& ach : cfg.child_range("achievement")) {
106  std::string id = ach["id"].str();
107 
108  if(id.empty()) {
109  ERR_CONFIG << content_for_ + " achievement missing id attribute:\n" << ach.debug();
110  } else if(id.find(',') != std::string::npos) {
111  ERR_CONFIG << content_for_ + " achievement missing id " << id << " contains a comma, skipping.";
112  continue;
113  } else {
115  }
116  }
117 }
void reload()
Reads the mainline achievements.cfg and then all the achievements of each installed add-on...
std::vector< achievement > achievements_
The achievements associated to this content.
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:264
child_itors child_range(config_key_type key)
Definition: config.cpp:344
std::string content_for_
The internal ID used for this content.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627
static lg::log_domain log_config("config")
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:350
void process_achievements_file(const config &cfg, const std::string &content_source)
Processes a config object to add new achievements to achievement_list_.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:39
std::string path
Definition: game_config.cpp:39
bool achievement(const std::string &content_for, const std::string &id)
Definition: general.cpp:1019
const char * what() const noexcept
Definition: exceptions.hpp:36
#define ERR_CONFIG
config read_achievements_file(const std::string &path)
Reads an achievements.cfg file into a config.
Declarations for File-IO.
std::vector< achievement_group > achievement_list_
int progress_achievement(const std::string &content_for, const std::string &id, int limit, int max_progress, int amount)
Increments the achievement&#39;s current progress by amount if it hasn&#39;t already been completed...
Definition: general.cpp:1061
achievement_group(const config &cfg)
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:28
std::string get_addons_dir()
Standard logging facilities (interface).
#define e
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.