The Battle for Wesnoth  1.17.4+dev
saved_game.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2022
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * Some information about savefiles:
17  *
18  * A savefile can contain:
19  *
20  * - General information (toplevel attributes, [multiplayer])
21  * This is present in all savefiles
22  *
23  * - [statistics]
24  * This is present in all savefiles but it's not handled by playcampaign/play_controller/saved_game.
25  * It's handled by savegame.cpp
26  *
27  * - [snapshot]
28  * If a savegame was saved during a scenario this contains a snapshot of the game at the point when
29  * it was saved.
30  *
31  * - [carryover_sides_start]
32  * At start-of-scenario saves this contains data from the previous scenario that was preserved.
33  *
34  * - [carryover_sides]
35  * In savefile made during the game, this tag contains data from [carryover_sides_start] that was not
36  * used in the current scenario but should be saved for a next scenario
37  *
38  * - [replay_start]
39  * A snapshot made very early to replay the game from.
40  *
41  * - [replay]
42  * A record of game actions that was made between the creation of [replay_start] and [snapshot].
43  *
44  *
45  * The following types of savegames are known:
46  *
47  * - Start of scenario savefiles
48  * These files only contain general information, statistics, and [carryover_sides_start]. When these
49  * saves are loaded, the scenario data is loaded form the game config using the next_scenario attribute
50  * from [carryover_sides_start].
51  *
52  * - Expanded Start of scenario savefiles
53  * Similar to normal Start-of-scenario savefiles, but the also contain a [scenario] that contains the
54  * scenario data. This type is only used internally and usually doesn't get written to the disk.
55  *
56  * - In-game savefile
57  * These files contain general information, statistics, [snapshot], [replay], [replay_start], [snapshot],
58  * and [carryover_sides]. These files don't contain a [carryover_sides_start] because both starting points
59  * ([replay_start] and [snapshot]) were made after [carryover_sides_start] was merged into the scenario.
60  *
61  * - Replay savefiles
62  * Like a in-game save made during linger mode, but without the [snapshot].
63  */
64 
65 #include "saved_game.hpp"
66 
67 #include "carryover.hpp"
68 #include "config.hpp"
69 #include "cursor.hpp"
70 #include "formula/string_utils.hpp"
71 #include "game_config_manager.hpp"
73 #include "log.hpp"
74 #include "random.hpp"
76 #include "side_controller.hpp"
77 #include "statistics.hpp"
78 #include "variable.hpp" // for config_variable_set
79 #include "variable_info.hpp"
80 
81 #include <cassert>
82 #include <iomanip>
83 
84 static lg::log_domain log_engine("engine");
85 #define ERR_NG LOG_STREAM(err, log_engine)
86 #define WRN_NG LOG_STREAM(warn, log_engine)
87 #define LOG_NG LOG_STREAM(info, log_engine)
88 #define DBG_NG LOG_STREAM(debug, log_engine)
89 
90 namespace
91 {
92 bool variable_to_bool(const config& vars, const std::string& expression)
93 {
94  std::string res = utils::interpolate_variables_into_string(expression, config_variable_set(vars));
95  return res == "true" || res == "yes" || res == "1";
96 }
97 
98 // helper objects for saved_game::expand_mp_events()
99 struct modevents_entry
100 {
101  modevents_entry(const std::string& _type, const std::string& _id)
102  : type(_type)
103  , id(_id)
104  {
105  }
106 
107  std::string type;
108  std::string id;
109 };
110 
111 bool is_illegal_file_char(char c)
112 {
113  return c == '/' || c == '\\' || c == ':' || (c >= 0x00 && c < 0x20)
114 #ifdef _WIN32
115  || c == '?' || c == '|' || c == '<' || c == '>' || c == '*' || c == '"'
116 #endif
117  ;
118 }
119 
120 } // end anon namespace
121 
123  : has_carryover_expanded_(false)
124  , carryover_(carryover_info().to_config())
125  , replay_start_()
126  , classification_()
127  , mp_settings_()
128  , starting_point_type_(starting_point::NONE)
129  , starting_point_()
130  , replay_data_()
131  , skip_story_(false)
132 {
133 }
134 
136  : has_carryover_expanded_(false)
137  , carryover_()
138  , replay_start_()
139  , classification_(cfg)
140  , mp_settings_()
142  , starting_point_()
143  , replay_data_()
144  , skip_story_(false)
145 {
146  set_data(cfg);
147 }
148 
151  , carryover_(state.carryover_)
154  , mp_settings_(state.mp_settings_)
157  , replay_data_(state.replay_data_)
158  , skip_story_(state.skip_story_)
159 {
160 }
161 
163 {
164  carryover_.swap(carryover_sides_start);
165  has_carryover_expanded_ = false;
166 }
167 
169 {
170  if(has_carryover_expanded_ || !carryover_["random_seed"].empty()) {
171  return;
172  }
173 
174  std::stringstream stream;
175  stream << std::setfill('0') << std::setw(8) << std::hex << randomness::generator->get_random_int(0, INT_MAX);
176  carryover_["random_seed"] = stream.str();
177  carryover_["random_calls"] = 0;
178 }
179 
181 {
182  write_general_info(out);
184 
185  if(!replay_start_.empty()) {
186  out.write_child("replay_start", replay_start_);
187  }
188 
189  out.open_child("replay");
190  replay_data_.write(out);
191 
192  out.close_child("replay");
193  write_carryover(out);
194 }
195 
197 {
199  out.write_child("snapshot", starting_point_);
201  out.write_child("scenario", starting_point_);
202  }
203 }
204 
206 {
207  assert(not_corrupt());
208  out.write_child(has_carryover_expanded_ ? "carryover_sides" : "carryover_sides_start", carryover_);
209 }
210 
212 {
214  out.write_child("multiplayer", mp_settings_.to_config());
215 }
216 
218 {
219  const bool is_loaded_game = starting_point_type_ != starting_point::SCENARIO;
220  const bool is_multiplayer_tag = classification().get_tagname() == "multiplayer";
222 
223  static const std::vector<std::string> team_defaults {
224  "carryover_percentage",
225  "carryover_add",
226  };
227 
228  if(const config& campaign = game_config.find_child("campaign", "id", classification_.campaign)) {
229  bool require_campaign = campaign["require_campaign"].to_bool(true);
230  starting_point_["require_scenario"] = require_campaign;
231  }
232 
233  for(config& side : starting_point_.child_range("side")) {
234  // Set save_id default value directly after loading to its default to prevent different default behaviour in
235  // mp_connect code and sp code.
236 
237  if(side["no_leader"].to_bool()) {
238  side["leader_lock"] = true;
239  side.remove_attribute("type");
240  }
241 
242  if(side["save_id"].empty()) {
243  side["save_id"] = side["id"];
244  }
245 
246  if(!is_multiplayer_tag && side["side_name"].blank()) {
247  side["side_name"] = side["name"];
248  }
249 
250  if(!is_loaded_game && !side["current_player"].empty()) {
251  ERR_NG << "Removed invalid 'current_player' attribute from [side] while loading a scenario. Consider using "
252  "'side_name' instead\n";
253 
254  side["current_player"] = config::attribute_value();
255  }
256 
257  // Set some team specific values to their defaults specified in scenario
258  for(const std::string& att_name : team_defaults) {
259  const config::attribute_value* scenario_value = starting_point_.get(att_name);
260  config::attribute_value& team_value = side[att_name];
261 
262  if(scenario_value && team_value.empty()) {
263  team_value = *scenario_value;
264  }
265  }
266  }
267 }
268 
270 {
273 
275  const config& scenario =
276  game_config.find_child(classification().get_tagname(), "id", carryover_["next_scenario"]);
277 
278  if(scenario) {
280  starting_point_ = scenario;
281 
282  // A hash has to be generated using an unmodified scenario data.
283  mp_settings_.hash = scenario.hash();
284 
286 
287  update_label();
288  set_defaults();
289  } else {
290  ERR_NG << "Couldn't find [" << classification().get_tagname() << "] with id=" << carryover_["next_scenario"] << std::endl;
293  }
294  }
295 }
296 
298 {
299  const std::string version_default = starting_point_["addon_id"].empty() ? game_config::wesnoth_version.str() : "";
300  config scenario;
301  scenario["id"] = starting_point_["addon_id"].str("mainline");
302  scenario["name"] = starting_point_["addon_title"].str("mainline");
303  scenario["version"] = starting_point_["addon_version"].str(version_default);
304  scenario["min_version"] = starting_point_["addon_min_version"];
305  scenario["required"] = starting_point_["require_scenario"].to_bool(false);
306  config& content = scenario.add_child("content");
307  content["id"] = starting_point_["id"];
308  content["name"] = starting_point_["name"];
309  content["type"] = "scenario";
310 
312 }
313 
314 // "non scenario" at the time of writing this meaning any era, campaign, mods, or resources (see expand_mp_events() below).
315 void saved_game::load_non_scenario(const std::string& type, const std::string& id, size_t pos)
316 {
317  if(const config& cfg = game_config_manager::get()->game_config().find_child(type, "id", id)) {
318  // Note the addon_id if this mod is required to play the game in mp.
319  std::string require_attr = "require_" + type;
320 
321  // By default, eras have "require_era = true", and mods have "require_modification = false".
322  // anything with no addon_id is from mainline, and therefore isn't required in the sense that all players already have it
323  const bool require_default = cfg["addon_id"].empty() ? false : type == "era";
324  const std::string version_default = cfg["addon_id"].empty() ? game_config::wesnoth_version.str() : "";
325  config non_scenario;
326  // if there's no addon_id, then this isn't an add-on
327  non_scenario["id"] = cfg["addon_id"].str("mainline");
328  non_scenario["name"] = cfg["addon_title"].str("mainline");
329  non_scenario["version"] = cfg["addon_version"].str(version_default);
330  non_scenario["min_version"] = cfg["addon_min_version"];
331  non_scenario["required"] = cfg[require_attr].to_bool(require_default);
332  config& content = non_scenario.add_child("content");
333  content["id"] = id;
334  content["name"] = cfg["addon_title"].str(cfg["name"].str(""));
335  content["type"] = type;
336 
338 
339  // Copy events
340  for(const config& modevent : cfg.child_range("event")) {
341  if(modevent["enable_if"].empty()
342  || variable_to_bool(carryover_.child_or_empty("variables"), modevent["enable_if"])
343  ) {
344  starting_point_.add_child_at_total("event", modevent, pos++);
345  }
346  }
347 
348  // Copy lua
349  for(const config& modlua : cfg.child_range("lua")) {
350  starting_point_.add_child_at_total("lua", modlua, pos++);
351  }
352 
353  // Copy modify_unit_type
354  for(const config& modlua : cfg.child_range("modify_unit_type")) {
355  starting_point_.add_child_at_total("modify_unit_type", modlua, pos++);
356  }
357 
358  // Copy load_resource
359  for(const config& load_resource : cfg.child_range("load_resource")) {
360  starting_point_.add_child_at_total("load_resource", load_resource, pos++);
361  }
362  } else {
363  // TODO: A user message instead?
364  ERR_NG << "Couldn't find [" << type << "] with id=" << id << std::endl;
365  }
366 }
367 
368 // Gets the ids of the mp_era and modifications which were set to be active, then fetches these configs from the
369 // game_config and copies their [event] and [lua] to the starting_point_.
370 // At this time, also collect the addon_id attributes which appeared in them and put this list in the addon_ids
371 // attribute of the mp_settings.
373 {
374  expand_scenario();
375 
376  if(starting_point_type_ == starting_point::SCENARIO && !starting_point_["has_mod_events"].to_bool(false)) {
377  std::vector<modevents_entry> mods;
378  std::set<std::string> loaded_resources;
379 
380  std::transform(classification_.active_mods.begin(), classification_.active_mods.end(), std::back_inserter(mods),
381  [](const std::string& id) { return modevents_entry("modification", id); }
382  );
383 
384  // We don't want the error message below if there is no era (= if this is a sp game).
385  if(!classification_.era_id.empty()) {
386  mods.emplace_back("era", classification_.era_id);
387  }
388 
389  if(!classification_.campaign.empty()) {
390  mods.emplace_back("campaign", classification_.campaign);
391  }
392 
393  for(modevents_entry& mod : mods) {
395  }
396  mods.clear();
397 
398  while(starting_point_.has_child("load_resource")) {
399  assert(starting_point_.child_count("load_resource") > 0);
400  std::string id = starting_point_.child("load_resource")["id"];
401  size_t pos = starting_point_.find_total_first_of("load_resource");
402  starting_point_.remove_child("load_resource", 0);
403  if(loaded_resources.find(id) == loaded_resources.end()) {
404  loaded_resources.insert(id);
405  load_non_scenario("resource", id, pos);
406  }
407  }
408  starting_point_["has_mod_events"] = true;
409  starting_point_["loaded_resources"] = utils::join(loaded_resources);
410  }
411 }
412 
414 {
416  std::vector<modevents_entry> mods;
417 
418  std::transform(classification_.active_mods.begin(), classification_.active_mods.end(), std::back_inserter(mods),
419  [](const std::string& id) { return modevents_entry("modification", id); }
420  );
421 
422  mods.emplace_back("era", classification_.era_id);
423  mods.emplace_back("multiplayer", get_scenario_id());
424  mods.emplace_back("campaign", classification().campaign);
425 
426  config& variables = carryover_.child_or_add("variables");
427 
428  for(modevents_entry& mod : mods) {
429  if(const config& cfg = mp_settings().options.find_child(mod.type, "id", mod.id)) {
430  for(const config& option : cfg.child_range("option")) {
431  try {
432  variable_access_create(option["id"], variables).as_scalar() = option["value"];
433  } catch(const invalid_variablename_exception&) {
434  ERR_NG << "variable " << option["id"] << "cannot be set to " << option["value"] << std::endl;
435  }
436  }
437  } else {
438  LOG_NG << "Couldn't find [" << mod.type << "] with id=" << mod.id << " for [option]s" << std::endl;
439  }
440  }
441  }
442 }
443 
444 static void inherit_scenario(config& scenario, config& map_scenario)
445 {
446  config sides;
447  sides.splice_children(map_scenario, "side");
448  scenario.append_children(map_scenario);
449  scenario.inherit_attributes(map_scenario);
450  for(config& side_from : sides.child_range("side")) {
451  config& side_to = scenario.find_child("side", "side", side_from["side"]);
452  if(side_to) {
453  side_to.inherit_attributes(side_from);
454  side_to.append_children(side_from);
455  } else {
456  scenario.add_child("side", side_from);
457  }
458  }
459 }
460 
462 {
463  if(scenario["map_data"].empty() && !scenario["map_file"].empty()) {
464  std::string map_data = filesystem::read_map(scenario["map_file"]);
465  if(map_data.find("map_data") != std::string::npos) {
466  // we have a scenario, gnerated by the editor
467  config map_data_cfg;
468  read(map_data_cfg, map_data);
469  inherit_scenario(scenario, map_data_cfg);
470  } else {
471  // we have an plain map_data file
472  scenario["map_data"] = map_data;
473  }
474  }
475 }
476 
478 {
479  expand_scenario();
480 
482  // If the entire scenario should be randomly generated
483  if(!starting_point_["scenario_generation"].empty()) {
484  LOG_NG << "randomly generating scenario...\n";
485  const cursor::setter cursor_setter(cursor::WAIT);
486 
487  config scenario_new =
488  random_generate_scenario(starting_point_["scenario_generation"], starting_point_.child("generator"), &carryover_.child_or_empty("variables"));
489 
491  starting_point_ = std::move(scenario_new);
492 
493  update_label();
494  set_defaults();
495  }
496 
497  // If no map_data is provided, try to load the specified file directly
499  // If the map should be randomly generated
500  // We don’t want that we accidentally to this twice so we check for starting_point_["map_data"].empty()
501  if(starting_point_["map_data"].empty() && !starting_point_["map_generation"].empty()) {
502  LOG_NG << "randomly generating map...\n";
503  const cursor::setter cursor_setter(cursor::WAIT);
504 
505  starting_point_["map_data"] =
506  random_generate_map(starting_point_["map_generation"], starting_point_.child("generator"), &carryover_.child_or_empty("variables"));
507  }
508  }
509 }
510 
511 void saved_game::post_scenario_generation(const config& old_scenario, config& generated_scenario)
512 {
513  static const std::vector<std::string> attributes_to_copy {
514  "id",
515  "addon_id",
516  "addon_title",
517  "addon_version",
518  "addon_min_version",
519  "require_scenario",
520  };
521 
522  // TODO: should we add "description" to this list?
523  // TODO: in theory it is possible that whether the scenario is required depends on the generated scenario, so maybe remove require_scenario from this list.
524 
525  for(const auto& str : attributes_to_copy) {
526  generated_scenario[str] = old_scenario[str];
527  }
528 
529  // Preserve "story" from the scenario toplevel.
530  // Note that it does not delete [story] tags in generated_scenario, so you can still have your story
531  // dependent on the generated scenario.
532  for(const config& story : old_scenario.child_range("story")) {
533  generated_scenario.add_child("story", story);
534  }
535 }
536 
537 
539 {
540  expand_scenario();
542  carryover_info sides(carryover_);
543 
545  for(config& side_cfg : get_starting_point().child_range("side")) {
546  sides.transfer_all_to(side_cfg);
547  }
548 
549  carryover_ = sides.to_config();
551  }
552 }
553 
554 bool saved_game::valid() const
555 {
557 }
558 
560 {
562  starting_point_.swap(snapshot);
563 
564  return starting_point_;
565 }
566 
568 {
570  starting_point_.swap(scenario);
571 
572  has_carryover_expanded_ = false;
573 
574  update_label();
575 }
576 
578 {
581 }
582 
584 {
585  return starting_point_;
586 }
587 
589 {
590  if(!replay_start_.empty()) {
591  return replay_start_;
592  }
593 
595  // Try to load the scenario form game config or from [scenario] if there is no [replay_start]
596  expand_scenario();
598  }
599 
601  return starting_point_;
602  }
603 
604  return replay_start_.child("some_non_existet_invalid");
605 }
606 
608 {
610 
611  carryover_info sides(starting_point_, true);
612 
614  sides.rng().rotate_random();
615 
616  carryover_ = sides.to_config();
617 
618  has_carryover_expanded_ = false;
619 
622 
623  remove_snapshot();
624 }
625 
627 {
628  // TODO: remove this code duplication with write_... functions.
630 
631  if(!replay_start_.empty()) {
632  r.add_child("replay_start", replay_start_);
633  }
634 
635  replay_data_.write(r.add_child("replay"));
636 
638  r.add_child("snapshot", starting_point_);
640  r.add_child("scenario", starting_point_);
641  }
642 
643  r.add_child(has_carryover_expanded_ ? "carryover_sides" : "carryover_sides_start", carryover_);
644  r.add_child("multiplayer", mp_settings_.to_config());
645 
646  return r;
647 }
648 
649 std::string saved_game::get_scenario_id() const
650 {
651  std::string scenario_id;
652 
654  scenario_id = starting_point_["id"].str();
655  } else if(!has_carryover_expanded_) {
656  scenario_id = carryover_["next_scenario"].str();
657  } else if(!replay_start_.empty()) {
658  scenario_id = replay_start_["id"].str();
659  } else {
660  assert(!"cannot figure out scenario_id");
661  throw "assertion ignored";
662  }
663 
664  return scenario_id == "null" ? "" : scenario_id;
665 }
666 
668 {
669  return true;
670 }
671 
673 {
674  std::string& label = classification().label;
675 
676  if(classification().abbrev.empty()) {
677  label = starting_point_["name"].str();
678  } else {
679  label = classification().abbrev + "-" + starting_point_["name"];
680  }
681 
682  label.erase(std::remove_if(label.begin(), label.end(), is_illegal_file_char), label.end());
683  std::replace(label.begin(), label.end(), '_', ' ');
684 }
685 
687 {
688  for(config& side : starting_point_.child_range("side")) {
689  // for humans "goto_x/y" is used for multi-turn-moves
690  // for the ai "goto_x/y" is a way for wml to order the ai to move a unit to a certain place.
691  // we want to cancel human order but not to break wml.
692  if(side["controller"] != side_controller::human) {
693  continue;
694  }
695 
696  for(config& unit : side.child_range("unit")) {
697  unit["goto_x"] = -999;
698  unit["goto_y"] = -999;
699  }
700  }
701 }
702 
704 {
705  for(config& side : starting_point_.child_range("side")) {
706  side.remove_attribute("is_local");
707  }
708 }
709 
711 {
712  swap(other);
713  return *this;
714 }
715 
717 {
718  carryover_.swap(other.carryover_);
719 
723 
727 
729 }
730 
732 {
733  log_scope("read_game");
734 
735  if(config& caryover_sides = cfg.child("carryover_sides")) {
736  carryover_.swap(caryover_sides);
738  } else if(config& caryover_sides_start = cfg.child("carryover_sides_start")) {
739  carryover_.swap(caryover_sides_start);
740  has_carryover_expanded_ = false;
741  } else {
742  carryover_.clear();
743  has_carryover_expanded_ = false;
744  }
745 
746  if(config& replay_start = cfg.child("replay_start")) {
748  } else {
750  }
751 
753 
754  // Serversided replays can contain multiple [replay]
755  for(config& replay : cfg.child_range("replay")) {
757  }
758 
760 
761  if(config& snapshot = cfg.child("snapshot")) {
763  starting_point_.swap(snapshot);
764  } else if(config& scenario = cfg.child("scenario")) {
766  starting_point_.swap(scenario);
767  } else {
770  }
771 
772  LOG_NG << "scenario: '" << carryover_["next_scenario"].str() << "'\n";
773 
774  if(const config& stats = cfg.child("statistics")) {
776  statistics::read_stats(stats);
777  }
778 
780  mp_settings_ = { cfg.child_or_empty("multiplayer") };
781 
782  cfg.clear();
783 }
784 
786 {
787  carryover_.clear();
788  classification_ = {};
789  has_carryover_expanded_ = false;
790  mp_settings_ = {};
791  replay_data_.swap({});
795 }
796 
797 void swap(saved_game& lhs, saved_game& rhs)
798 {
799  lhs.swap(rhs);
800 }
void check_require_scenario()
Add addon_id information if needed.
Definition: saved_game.cpp:297
bool empty() const
Tests for an attribute that either was never set or was set to "".
config replay_start_
snapshot made before the start event.
Definition: saved_game.hpp:151
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
void write_general_info(config_writer &out) const
Definition: saved_game.cpp:211
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with &#39;$&#39; in the string &#39;str&#39; with the equivalent ...
void write(const config &cfg)
std::string label
Name of the game (e.g.
This class represents a single unit of a specific type.
Definition: unit.hpp:120
void expand_scenario()
copies the content of a [scenario] with the correct id attribute from the game config into this objec...
Definition: saved_game.cpp:269
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:885
config & replay_start()
Definition: saved_game.hpp:123
Variant for storing WML attributes.
void set_scenario(config scenario)
Definition: saved_game.cpp:567
const config to_config()
Definition: carryover.cpp:240
void write_starting_point(config_writer &out) const
Definition: saved_game.cpp:196
void set_defaults()
does some post loading stuff must be used before passing the data to connect_engine ...
Definition: saved_game.cpp:217
void write_config(config_writer &out) const
writes the config information into a stream (file)
Definition: saved_game.cpp:180
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:394
unsigned child_count(config_key_type key) const
Definition: config.cpp:372
void write_carryover(config_writer &out) const
Definition: saved_game.cpp:205
config & add_child_at_total(config_key_type key, const config &val, size_t pos)
Definition: config.cpp:594
child_itors child_range(config_key_type key)
Definition: config.cpp:344
void unify_controllers()
Definition: saved_game.cpp:703
void load_game_config_for_game(const game_classification &classification, const std::string &scenario_id)
void expand_random_scenario()
takes care of generate_map=, generate_scenario=, map= attributes This should be called before expandi...
Definition: saved_game.cpp:477
bool valid() const
Definition: saved_game.cpp:554
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:780
#define LOG_NG
Definition: saved_game.cpp:87
void fresh_stats()
Definition: statistics.cpp:783
void merge_old_carryover(const carryover_info &old_carryover)
Definition: carryover.cpp:271
size_t find_total_first_of(config_key_type key, size_t start=0)
Definition: config.cpp:580
void clear()
Definition: saved_game.cpp:785
config & child_or_add(config_key_type key)
Returns a reference to the first child with the given key.
Definition: config.cpp:478
config starting_point_
The starting pos where the (non replay) game will be started from.
Definition: saved_game.hpp:161
config & set_snapshot(config snapshot)
Definition: saved_game.cpp:559
void clear()
Definition: config.cpp:920
static void post_scenario_generation(const config &old_scenario, config &generated_scenario)
copies attributes & tags from the &#39;outer&#39; [scenario] to the scenario that is generated by scenario_genera...
Definition: saved_game.cpp:511
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:223
void transfer_to(config &level)
Definition: carryover.cpp:211
void remove_attribute(config_key_type key)
Definition: config.cpp:217
Definitions for the interface to Wesnoth Markup Language (WML).
std::string get_scenario_id() const
Definition: saved_game.cpp:649
std::string random_generate_map(const std::string &name, const config &cfg, const config *vars)
Definition: map_create.cpp:45
config to_config() const
We failed to get a starting pos in expand_scenario.
void write_child(const std::string &key, const config &cfg)
void transfer_all_to(config &side_cfg)
Definition: carryover.cpp:185
const config & options()
Definition: game.cpp:562
static game_config_manager * get()
void swap(config &cfg)
Definition: config.cpp:1447
#define ERR_NG
Definition: saved_game.cpp:85
static void expand_map_file(config &scenario)
reads scenario["map_file"]
Definition: saved_game.cpp:461
void splice_children(config &src, const std::string &key)
Moves all the children with tag key from src to this.
Definition: config.cpp:664
const randomness::mt_rng & rng() const
Definition: carryover.hpp:94
void close_child(const std::string &key)
std::string label
What to show in the filter&#39;s drop-down list.
Definition: manager.cpp:217
void set_random_seed()
sets the random seed if that didn&#39;t already happen.
Definition: saved_game.cpp:168
std::vector< std::string > active_mods
void expand_mp_options()
adds values of [option]s into [carryover_sides_start][variables] so that they are applied in the next...
Definition: saved_game.cpp:413
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627
Class for writing a config out to a file in pieces.
unsigned all_children_count() const
Definition: config.cpp:384
const game_config_view & game_config() const
void open_child(const std::string &key)
void update_label()
sets classification().label to the correct value.
Definition: saved_game.cpp:672
void update_addon_requirements(const config &addon_cfg)
Takes a config with addon metadata (id, name, version, min_version) and adds it as a requirement for ...
void swap(saved_game &lhs, saved_game &rhs)
Implement non-member swap function for std::swap (calls saved_game::swap).
Definition: saved_game.cpp:797
void read_stats(const config &cfg)
Definition: statistics.cpp:773
config carryover_
depends on has_carryover_expanded_: if true: The carryover information for all sides from the previou...
Definition: saved_game.hpp:149
config & get_starting_point()
Definition: saved_game.cpp:583
void write(config_writer &out) const
bool skip_story_
Definition: saved_game.hpp:165
void load_non_scenario(const std::string &type, const std::string &id, size_t pos)
helper for expand_mp_events();
Definition: saved_game.cpp:315
starting_point starting_point_type_
Definition: saved_game.hpp:156
std::string campaign
The id of the campaign being played.
void set_data(config &cfg)
destroys the passed config.
Definition: saved_game.cpp:731
all_children_iterator erase(const all_children_iterator &i)
Definition: config.cpp:727
bool not_corrupt() const
Definition: saved_game.cpp:667
std::string read_map(const std::string &name)
void inherit_attributes(const config &c)
Merge the attributes of config &#39;c&#39; into this config, preserving this config&#39;s values.
Definition: config.cpp:1289
static void inherit_scenario(config &scenario, config &map_scenario)
Definition: saved_game.cpp:444
game_classification classification_
some general information of the game that doesn&#39;t change during the game
Definition: saved_game.hpp:153
std::string abbrev
the campaign abbreviation
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
const config & get_replay_starting_point()
Definition: saved_game.cpp:588
There is no scenario stating pos data (start-of-scenario).
Default, unset return value.
Definition: retval.hpp:32
We have a [scenario] (start-of-scenario) savefile.
Game configuration data as global variables.
Definition: build_info.cpp:60
mp_game_settings mp_settings_
Definition: saved_game.hpp:154
void rotate_random()
Resets the random to the 0 calls and the seed to the random this way we stay in the same sequence but...
Definition: mt_rng.cpp:74
void append_config(const config &data)
#define log_scope(description)
Definition: log.hpp:218
void expand_mp_events()
adds [event]s from [era] and [modification] into this scenario does NOT expand [option]s because vari...
Definition: saved_game.cpp:372
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
Definition: random.hpp:52
void expand_carryover()
merges [carryover_sides_start] into [scenario] and saves the rest into [carryover_sides] Removes [car...
Definition: saved_game.cpp:538
const version_info wesnoth_version(VERSION)
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:61
variable_info_mutable< variable_info_implementation::vi_policy_create > variable_access_create
&#39;Create if nonexistent&#39; access.
config & add_child(config_key_type key)
Definition: config.cpp:514
const config & find_child(config_key_type key, const std::string &name, const std::string &value) const
void swap(replay_recorder_base &other)
void swap(saved_game &other)
Definition: saved_game.cpp:716
void cancel_orders()
Definition: saved_game.cpp:686
replay_recorder_base replay_data_
Definition: saved_game.hpp:163
config random_generate_scenario(const std::string &name, const config &cfg, const config *vars)
Definition: map_create.cpp:57
game_classification & classification()
Definition: saved_game.hpp:55
void set_carryover_sides_start(config carryover_sides_start)
Definition: saved_game.cpp:162
saved_game & operator=(const saved_game &other)=delete
Standard logging facilities (interface).
std::string str() const
Serializes the version number into string form.
void convert_to_start_save()
converts a normal savegame form the end of a scenaio to a start-of-scenario savefile for the next sce...
Definition: saved_game.cpp:607
config to_config() const
Definition: saved_game.cpp:626
We have a [snapshot] (mid-game-savefile).
void remove_snapshot()
Definition: saved_game.cpp:577
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:465
config_attribute_value attribute_value
Variant for storing WML attributes.
Definition: config.hpp:214
static lg::log_domain log_engine("engine")
Some information about savefiles:
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
mock_char c
bool has_carryover_expanded_
Definition: saved_game.hpp:143
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
Definition: saved_game.hpp:59
void remove_child(config_key_type key, unsigned index)
Definition: config.cpp:732
std::string hash() const
Definition: config.cpp:1392
bool empty() const
Definition: config.cpp:941
std::string get_tagname() const