The Battle for Wesnoth  1.19.0-dev
create_engine.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2024
3  by Andrius Silinskas <silinskas.andrius@gmail.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 
16 #pragma once
17 
18 #include "config.hpp"
22 #include "mp_game_settings.hpp"
23 #include "utils/irdya_datetime.hpp"
24 
25 #include <numeric>
26 #include <string>
27 #include <utility>
28 #include <cctype>
29 
30 class saved_game;
31 class gamemap;
32 class game_config_view;
33 
34 namespace ng {
35 
36 static bool contains_ignore_case(const std::string& str1, const std::string& str2)
37 {
38  if(str2.size() > str1.size()) {
39  return false;
40  }
41 
42  for(std::size_t i = 0; i < str1.size() - str2.size() + 1; i++) {
43  bool ok = true;
44  for(std::size_t j = 0; j < str2.size(); j++) {
45  if(std::tolower(str1[i + j]) != std::tolower(str2[j])) {
46  ok = false;
47  break;
48  }
49  }
50 
51  if(ok) {
52  return true;
53  }
54  }
55 
56  return false;
57 }
58 
59 /** Base class for all level type classes. */
60 class level
61 {
62 public:
63  level(const config& data);
64  virtual ~level() = default;
65 
66  virtual void set_metadata() = 0;
67 
68  virtual bool can_launch_game() const = 0;
69  virtual bool player_count_filter(int player_count) const = 0;
70 
71  virtual std::string id() const
72  {
73  return data_["id"];
74  }
75 
76  virtual std::string name() const
77  {
78  return data_["name"];
79  }
80 
81  virtual std::string icon() const
82  {
83  return data_["icon"];
84  }
85 
86  virtual std::string description() const
87  {
88  return data_["description"];
89  }
90 
91  virtual bool allow_era_choice() const
92  {
93  return data_["allow_era_choice"].to_bool(true);
94  }
95 
96  void set_data(const config& data)
97  {
98  data_ = data;
99  }
100 
101  const config& data() const
102  {
103  return data_;
104  }
105 
107  {
108  return data_;
109  }
110 
111 protected:
113 
114 private:
115  level(const level&) = delete;
116  level& operator=(const level&) = delete;
117 };
118 
119 class scenario : public level
120 {
121 public:
122  scenario(const config& data);
123 
124  bool can_launch_game() const;
125 
126  void set_metadata();
127 
128  int num_players() const
129  {
130  return num_players_;
131  }
132 
133  std::string map_size() const;
134 
135  bool player_count_filter(int player_count) const
136  {
137  return num_players_ == player_count;
138  }
139 
140 protected:
141  void set_sides();
142 
143  std::unique_ptr<gamemap> map_;
144 
145  std::string map_hash_;
146 
147 private:
148  scenario(const scenario&) = delete;
149  scenario& operator=(const scenario&) = delete;
150 
152 };
153 
154 class user_map : public scenario
155 {
156 public:
157  user_map(const config& data, const std::string& name, gamemap* map);
158 
159  void set_metadata();
160 
161  /** For user maps, the id and name are the same. */
162  std::string id() const
163  {
164  return name_;
165  }
166 
167  std::string name() const
168  {
169  return name_;
170  }
171 
172  std::string description() const;
173 
174 private:
175  user_map(const user_map&) = delete;
176  user_map& operator=(const user_map&) = delete;
177 
178  std::string name_;
179 };
180 
181 class random_map : public scenario
182 {
183 public:
184  random_map(const config& data);
185 
186  const config& generator_data() const
187  {
188  return generator_data_;
189  }
190 
191  std::string generator_name() const
192  {
193  return generator_name_;
194  }
195 
197 
199  {
201  }
202 
203 private:
204  random_map(const random_map&) = delete;
205  random_map& operator=(const random_map&) = delete;
206 
208 
210  std::string generator_name_;
211 };
212 
213 class campaign : public level
214 {
215 public:
216  campaign(const config& data);
217 
218  bool can_launch_game() const;
219 
220  void set_metadata();
221 
222  void mark_if_completed();
223 
224  std::string id() const
225  {
226  return id_;
227  }
228 
229  bool allow_era_choice() const
230  {
231  return allow_era_choice_;
232  }
233 
234  int min_players() const
235  {
236  return min_players_;
237  }
238 
239  int max_players() const
240  {
241  return max_players_;
242  }
243 
244  bool player_count_filter(int player_count) const
245  {
246  return min_players_ <= player_count && max_players_ >= player_count;
247  }
248 
249  std::pair<utils::irdya_date, utils::irdya_date> dates() const
250  {
251  return dates_;
252  }
253 
254 private:
255  campaign(const campaign&) = delete;
256  campaign& operator=(const campaign&) = delete;
257 
258  std::string id_;
260  std::string image_label_;
263  std::pair<utils::irdya_date, utils::irdya_date> dates_;
264 };
265 
267 {
268 public:
269  explicit create_engine(saved_game& state);
270 
271  enum MP_EXTRA { ERA, MOD };
272 
274  {
275  std::string id;
276  std::string name;
277  std::string description;
278  const config* cfg;
279  };
280 
281  typedef std::shared_ptr<extras_metadata> extras_metadata_ptr;
282 
283  typedef std::shared_ptr<level> level_ptr;
284  typedef std::shared_ptr<scenario> scenario_ptr;
285  typedef std::shared_ptr<user_map> user_map_ptr;
286  typedef std::shared_ptr<random_map> random_map_ptr;
287  typedef std::shared_ptr<campaign> campaign_ptr;
288 
290 
291  void prepare_for_new_level();
293  void prepare_for_scenario();
294  void prepare_for_campaign(const std::string& difficulty = "");
295  void prepare_for_saved_game();
296  // random maps, user maps
297  void prepare_for_other();
298 
299  /**
300  * select_campaign_difficulty
301  *
302  * Launches difficulty selection gui and returns selected difficulty name.
303  *
304  * The gui can be bypassed by supplying a number from 1 to the number of
305  * difficulties available, corresponding to a choice of difficulty.
306  * This is useful for specifying difficulty via command line.
307  *
308  * @param set_value Preselected difficulty number. The default -1 launches the gui.
309  * @return Selected difficulty. Returns "FAIL" if set_value is invalid,
310  * and "CANCEL" if the gui is canceled.
311  */
312  std::string select_campaign_difficulty(int set_value = -1);
314  {
316  }
317 
318  void apply_level_filter(const std::string& name);
319  void apply_level_filter(int players);
320  void reset_level_filters();
321 
322  const std::string& level_name_filter() const
323  {
324  return level_name_filter_;
325  }
326 
327  int player_num_filter() const
328  {
329  return player_count_filter_;
330  }
331 
332  std::vector<level_ptr> get_levels_by_type_unfiltered(level_type::type type) const;
333  std::vector<level_ptr> get_levels_by_type(level_type::type type) const;
334 
335  std::vector<std::size_t> get_filtered_level_indices(level_type::type type) const;
336 
337  level& current_level() const;
338  const extras_metadata& current_era() const;
339 
341  {
343  }
344 
346  {
347  return current_level_type_;
348  }
349 
350  /** Wrapper to simplify the is-type-campaign-or-sp-campaign check. */
351  bool is_campaign() const
352  {
353  return current_level_type_ == level_type::type::campaign || current_level_type_ == level_type::type::sp_campaign;
354  }
355 
356  void set_current_level(const std::size_t index);
357 
358  void set_current_era_index(const std::size_t index, bool force = false);
359 
360  std::size_t current_era_index() const
361  {
362  return current_era_index_;
363  }
364 
365  const config& curent_era_cfg() const;
366 
367  const std::vector<extras_metadata_ptr>& get_const_extras_by_type(const MP_EXTRA extra_type) const;
368  std::vector<extras_metadata_ptr>& get_extras_by_type(const MP_EXTRA extra_type);
369 
370  bool toggle_mod(const std::string& id, bool force = false);
371 
372  bool generator_assigned() const;
373  bool generator_has_settings() const;
374  void generator_user_config();
375 
376  std::pair<level_type::type, int> find_level_by_id(const std::string& id) const;
377  int find_extra_by_id(const MP_EXTRA extra_type, const std::string& id) const;
378 
380  {
381  return *dependency_manager_;
382  }
383 
384  void init_active_mods();
385 
386  std::vector<std::string>& active_mods();
387  std::vector<extras_metadata_ptr> active_mods_data();
388 
390 
392 
393  /** Returns true if the current level has one or more [side] tags. */
395 
396 private:
397  create_engine(const create_engine&) = delete;
399 
400  void init_all_levels();
401  void init_extras(const MP_EXTRA extra_type);
402  void apply_level_filters();
403 
404  std::size_t map_level_index(std::size_t index) const;
405 
407  std::size_t current_level_index_;
408 
409  std::size_t current_era_index_;
410 
411  std::string level_name_filter_;
413 
414  struct type_list
415  {
416  explicit type_list() : games(), games_filtered() {}
417 
418  std::vector<level_ptr> games;
419  std::vector<std::size_t> games_filtered;
420 
421  void apply_filter(const int player_count, const std::string& name_filter)
422  {
423  games_filtered.clear();
424 
425  for(std::size_t i = 0; i < games.size(); i++) {
426  const bool num_players_match = player_count == 1 || games[i]->player_count_filter(player_count);
427 
428  if(contains_ignore_case(games[i]->name(), name_filter) && num_players_match) {
429  games_filtered.push_back(i);
430  }
431  }
432  }
433 
435  {
436  games_filtered.resize(games.size());
437  std::iota(games_filtered.begin(), games_filtered.end(), 0);
438  }
439  };
440 
441  std::map<level_type::type, type_list> type_map_;
442 
443  std::vector<std::string> user_map_names_;
444  std::vector<std::string> user_scenario_names_;
445 
446  std::vector<extras_metadata_ptr> eras_;
447  std::vector<extras_metadata_ptr> mods_;
448 
450 
451  // Never nullptr
452  std::unique_ptr<depcheck::manager> dependency_manager_;
453 
454  std::unique_ptr<map_generator> generator_;
455 
457 
458  /** Reference to the main game config. */
460 };
461 
462 } // end namespace ng
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
A class grating read only view to a vector of config objects, viewed as one config with all children ...
Encapsulates the map of the game.
Definition: map.hpp:172
campaign(const campaign &)=delete
std::pair< utils::irdya_date, utils::irdya_date > dates_
campaign(const config &data)
void mark_if_completed()
std::string image_label_
bool player_count_filter(int player_count) const
int max_players() const
int min_players() const
std::pair< utils::irdya_date, utils::irdya_date > dates() const
std::string id() const
std::string id_
bool can_launch_game() const
campaign & operator=(const campaign &)=delete
bool allow_era_choice() const
std::string level_name_filter_
int find_extra_by_id(const MP_EXTRA extra_type, const std::string &id) const
std::string get_selected_campaign_difficulty() const
create_engine(saved_game &state)
std::shared_ptr< campaign > campaign_ptr
std::vector< std::size_t > get_filtered_level_indices(level_type::type type) const
bool toggle_mod(const std::string &id, bool force=false)
const std::string & level_name_filter() const
void set_current_era_index(const std::size_t index, bool force=false)
std::string select_campaign_difficulty(int set_value=-1)
select_campaign_difficulty
std::vector< level_ptr > get_levels_by_type(level_type::type type) const
std::string selected_campaign_difficulty_
bool generator_has_settings() const
std::vector< std::string > & active_mods()
std::vector< std::string > user_map_names_
bool current_level_has_side_data()
Returns true if the current level has one or more [side] tags.
bool generator_assigned() const
level_type::type current_level_type() const
std::map< level_type::type, type_list > type_map_
void init_extras(const MP_EXTRA extra_type)
int player_num_filter() const
std::vector< extras_metadata_ptr > & get_extras_by_type(const MP_EXTRA extra_type)
std::shared_ptr< user_map > user_map_ptr
const std::vector< extras_metadata_ptr > & get_const_extras_by_type(const MP_EXTRA extra_type) const
void apply_level_filter(const std::string &name)
const depcheck::manager & dependency_manager() const
const extras_metadata & current_era() const
create_engine & operator=(const create_engine &)=delete
std::size_t current_era_index_
const config & curent_era_cfg() const
std::vector< extras_metadata_ptr > mods_
std::unique_ptr< depcheck::manager > dependency_manager_
std::vector< std::string > user_scenario_names_
std::vector< extras_metadata_ptr > active_mods_data()
std::shared_ptr< level > level_ptr
void set_current_level_type(const level_type::type type)
const game_config_view & game_config_
Reference to the main game config.
std::shared_ptr< random_map > random_map_ptr
std::unique_ptr< map_generator > generator_
std::pair< level_type::type, int > find_level_by_id(const std::string &id) const
saved_game & get_state()
bool is_campaign() const
Wrapper to simplify the is-type-campaign-or-sp-campaign check.
std::vector< extras_metadata_ptr > eras_
void prepare_for_campaign(const std::string &difficulty="")
std::vector< level_ptr > get_levels_by_type_unfiltered(level_type::type type) const
const mp_game_settings & get_parameters()
std::shared_ptr< extras_metadata > extras_metadata_ptr
saved_game & state_
void set_current_level(const std::size_t index)
std::size_t map_level_index(std::size_t index) const
void prepare_for_era_and_mods()
std::size_t current_era_index() const
void init_generated_level_data()
level_type::type current_level_type_
std::size_t current_level_index_
create_engine(const create_engine &)=delete
level & current_level() const
std::shared_ptr< scenario > scenario_ptr
Note to all triers: It's not guaranteed that the specified component will be selected (if the user de...
Definition: depcheck.hpp:50
Base class for all level type classes.
const config & data() const
virtual bool player_count_filter(int player_count) const =0
level & operator=(const level &)=delete
virtual bool can_launch_game() const =0
void set_data(const config &data)
level(const level &)=delete
virtual std::string id() const
virtual std::string name() const
virtual ~level()=default
config & data()
virtual void set_metadata()=0
virtual bool allow_era_choice() const
virtual std::string icon() const
virtual std::string description() const
level(const config &data)
bool generate_whole_scenario() const
bool generate_whole_scenario_
const config & generator_data() const
random_map & operator=(const random_map &)=delete
random_map(const config &data)
random_map(const random_map &)=delete
std::string generator_name() const
map_generator * create_map_generator() const
std::string generator_name_
std::string map_hash_
scenario & operator=(const scenario &)=delete
int num_players() const
std::unique_ptr< gamemap > map_
scenario(const config &data)
bool player_count_filter(int player_count) const
void set_metadata()
scenario(const scenario &)=delete
std::string map_size() const
bool can_launch_game() const
std::string id() const
For user maps, the id and name are the same.
std::string name_
std::string name() const
user_map & operator=(const user_map &)=delete
user_map(const config &data, const std::string &name, gamemap *map)
std::string description() const
user_map(const user_map &)=delete
std::size_t i
Definition: function.cpp:968
static bool contains_ignore_case(const std::string &str1, const std::string &str2)
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
std::vector< std::size_t > games_filtered
std::vector< level_ptr > games
void apply_filter(const int player_count, const std::string &name_filter)