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