The Battle for Wesnoth  1.15.0-dev
savegame.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by Jörg Hinrichs, refactored from various
3  places formerly created by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project http://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 <boost/iostreams/filter/gzip.hpp>
17 
18 #include "savegame.hpp"
19 
20 #include "save_index.hpp"
21 #include "carryover.hpp"
22 #include "cursor.hpp"
23 #include "format_time_summary.hpp"
24 #include "formatter.hpp"
25 #include "formula/string_utils.hpp"
26 #include "game_end_exceptions.hpp"
27 #include "game_errors.hpp"
28 #include "preferences/game.hpp"
29 #include "gettext.hpp"
32 #include "gui/dialogs/message.hpp"
35 #include "gui/widgets/settings.hpp"
36 #include "gui/widgets/retval.hpp"
37 #include "log.hpp"
38 #include "persist_manager.hpp"
39 #include "resources.hpp"
40 #include "save_index.hpp"
41 #include "saved_game.hpp"
43 #include "serialization/parser.hpp"
45 #include "statistics.hpp"
46 #include "version.hpp"
47 #include "video.hpp"
48 
49 #include <algorithm>
50 
51 static lg::log_domain log_engine("engine");
52 #define LOG_SAVE LOG_STREAM(info, log_engine)
53 #define ERR_SAVE LOG_STREAM(err, log_engine)
54 
55 static lg::log_domain log_enginerefac("enginerefac");
56 #define LOG_RG LOG_STREAM(info, log_enginerefac)
57 
58 
59 namespace savegame {
60 
61 bool save_game_exists(std::string name, compression::format compressed)
62 {
63  name += compression::format_extension(compressed);
65 }
66 
67 void clean_saves(const std::string& label)
68 {
69  std::vector<save_info> games = get_saves_list();
70  std::string prefix = label + "-" + _("Auto-Save");
71  LOG_SAVE << "Cleaning saves with prefix '" << prefix << "'\n";
72  for (std::vector<save_info>::iterator i = games.begin(); i != games.end(); ++i) {
73  if (i->name().compare(0, prefix.length(), prefix) == 0) {
74  LOG_SAVE << "Deleting savegame '" << i->name() << "'\n";
75  delete_game(i->name());
76  }
77  }
78 }
79 
81  : game_config_(game_config)
82  , gamestate_(gamestate)
83  , load_data_()
84 {}
85 
87 {
88  if(load_data_.summary["corrupt"].to_bool()) {
89  return false;
90  }
91 
92  std::string campaign_id = load_data_.summary["campaign"];
93 
94  for(const config &campaign : game_config_.child_range("campaign"))
95  {
96  if(campaign["id"] != campaign_id) {
97  continue;
98  }
99 
100  gui2::dialogs::campaign_difficulty difficulty_dlg(campaign);
101  difficulty_dlg.show();
102 
103  // Return if canceled, since otherwise load_data_.difficulty will be set to 'CANCEL'
104  if (difficulty_dlg.get_retval() != gui2::retval::OK) {
105  return false;
106  }
107 
108  load_data_.difficulty = difficulty_dlg.selected_difficulty();
109 
110  // Exit loop
111  break;
112  }
113 
114  return true;
115 }
116 
117 // Called only by play_controller to handle in-game attempts to load. Instead of returning true,
118 // throws a "load_game_exception" to signal a resulting load game request.
120 {
121  if(CVideo::get_singleton().faked()) {
122  return false;
123  }
124 
126  return false;
127  }
128 
129  if(load_data_.filename.empty()) {
130  return false;
131  }
132 
134  if(!show_difficulty_dialog()) {
135  return false;
136  }
137  }
138 
140 
141  // Confirm the integrity of the file before throwing the exception.
142  // Use the summary in the save_index for this.
143  const config & summary = save_index_manager.get(load_data_.filename);
144 
145  if (summary["corrupt"].to_bool(false)) {
147  _("The file you have tried to load is corrupt: '"));
148  return false;
149  }
150 
151  if (!loadgame::check_version_compatibility(summary["version"].str())) {
152  return false;
153  }
154 
155  throw load_game_exception(std::move(load_data_));
156 }
157 
159 {
160  bool skip_version_check = true;
161 
162  if(load_data_.filename.empty()){
164  return false;
165  }
166  skip_version_check = false;
168  }
169 
170  if(load_data_.filename.empty()) {
171  return false;
172  }
173 
175  if(!show_difficulty_dialog()) {
176  return false;
177  }
178  }
179 
180  std::string error_log;
182 
184 
185  for (config& side : load_data_.load_config.child_range("side")) {
186  side.remove_attribute("is_local");
187  }
188 
189  if(!error_log.empty()) {
190  try {
192  _("Warning: The file you have tried to load is corrupt. Loading anyway.\n") +
193  error_log);
194  } catch (const utf8::invalid_utf8_exception&) {
196  _("Warning: The file you have tried to load is corrupt. Loading anyway.\n") +
197  std::string("(UTF-8 ERROR)"));
198  }
199  }
200 
201  if (!load_data_.difficulty.empty()){
203  }
204  // read classification to for loading the game_config config object.
206 
207  if (skip_version_check) {
208  return true;
209  }
210 
212 }
213 
215 {
217 }
218 
220 {
221  if (save_version == game_config::wesnoth_version) {
222  return true;
223  }
224 
226 
227  // Even minor version numbers indicate stable releases which are
228  // compatible with each other.
229  if (wesnoth_version.minor_version() % 2 == 0 &&
230  wesnoth_version.major_version() == save_version.major_version() &&
231  wesnoth_version.minor_version() == save_version.minor_version())
232  {
233  return true;
234  }
235 
236  // Do not load if too old. If either the savegame or the current
237  // game has the version 'test', load. This 'test' version is never
238  // supposed to occur, except when Soliton is testing MP servers.
239  if (save_version < game_config::min_savegame_version &&
240  save_version != game_config::test_version &&
241  wesnoth_version != game_config::test_version)
242  {
243  const std::string message = _("This save is from an old, unsupported version ($version_number|) and cannot be loaded.");
244  utils::string_map symbols;
245  symbols["version_number"] = save_version.str();
247  return false;
248  }
249 
251  const std::string message = _("This save is from a different version of the game ($version_number|). Do you wish to try to load it?");
252  utils::string_map symbols;
253  symbols["version_number"] = save_version.str();
254  const int res = gui2::show_message(_("Load Game"), utils::interpolate_variables_into_string(message, &symbols),
256  return res == gui2::retval::OK;
257  }
258 
259  return true;
260 }
261 
263 {
265 }
266 
268 {
270  return false;
271  }
272 
273 
275  if(load_data_.filename.empty()) {
276  return false;
277  }
278 
279  // read_save_file needs to be called before we can verify the classification so the data has
280  // been populated. Since we do that, we report any errors in that process first.
281  std::string error_log;
282  {
284  log_scope("load_game");
285 
288  }
289 
290  if(!error_log.empty()) {
292  _("The file you have tried to load is corrupt: '") +
293  error_log);
294  return false;
295  }
296 
298  gui2::show_transient_message(_("Load Game"), _("Replays are not supported in multiplayer mode."));
299  return false;
300  }
301 
302  // We want to verify the game classification before setting the data, so we don't check on
303  // gamestate_.classification() and instead construct a game_classification object manually.
304  if(game_classification(load_data_.load_config).campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
305  gui2::show_transient_error_message(_("This is not a multiplayer save."));
306  return false;
307  }
308 
309  set_gamestate();
310 
312 }
313 
315 {
316  const config &replay_start = cfg.child("replay_start");
317  if (!replay_start) return;
318 
319  const config &era = replay_start.child("era");
320  if (!era) return;
321 
322  config &snapshot = cfg.child("snapshot");
323  if (!snapshot) return;
324 
325  snapshot.add_child("era", era);
326 }
327 
328 savegame::savegame(saved_game& gamestate, const compression::format compress_saves, const std::string& title)
329  : filename_()
330  , title_(title)
331  , gamestate_(gamestate)
332  , error_message_(_("The game could not be saved: "))
333  , show_confirmation_(false)
334  , compress_saves_(compress_saves)
335 {}
336 
337 bool savegame::save_game_automatic(bool ask_for_overwrite, const std::string& filename)
338 {
339  if (filename.empty())
340  filename_ = create_filename();
341  else
342  filename_ = filename;
343 
344  if (ask_for_overwrite){
345  if (!check_overwrite()) {
346  return save_game_interactive("", savegame::OK_CANCEL);
347  }
348  }
349 
350  return save_game();
351 }
352 
353 bool savegame::save_game_interactive(const std::string& message, DIALOG_TYPE dialog_type)
354 {
355  show_confirmation_ = true;
356  filename_ = create_filename();
357 
358  const int res = show_save_dialog(message, dialog_type);
359 
360  if (res == 2) {
361  throw_quit_game_exception(); //Quit game
362  }
363 
364  if (res == gui2::retval::OK && check_overwrite()) {
365  return save_game();
366  }
367 
368  return false;
369 }
370 
371 int savegame::show_save_dialog(const std::string& message, DIALOG_TYPE dialog_type)
372 {
373  int res = 0;
374 
375  if (dialog_type == OK_CANCEL){
376  gui2::dialogs::game_save dlg(filename_, title_);
377  dlg.show();
378  res = dlg.get_retval();
379  }
380  else if (dialog_type == YES_NO){
381  gui2::dialogs::game_save_message dlg(filename_, title_, message);
382  dlg.show();
383  res = dlg.get_retval();
384  }
385 
386  if (!check_filename(filename_)) {
387  res = gui2::retval::CANCEL;
388  }
389 
390  return res;
391 }
392 
393 bool savegame::check_overwrite()
394 {
395  if(!save_game_exists(filename_, compress_saves_)) {
396  return true;
397  }
398 
399  std::ostringstream message;
400  message << _("Save already exists. Do you want to overwrite it?") << "\n" << _("Name: ") << filename_;
401  const int res = gui2::show_message(_("Overwrite?"), message.str(), gui2::dialogs::message::yes_no_buttons);
402  return res == gui2::retval::OK;
403 
404 }
405 
406 bool savegame::check_filename(const std::string& filename)
407 {
408  if (filesystem::is_compressed_file(filename)) {
409  gui2::show_error_message(_("Save names should not end on '.gz' or '.bz2'. "
410  "Please remove the extension."));
411  return false;
412  }
413 
414  return true;
415 }
416 
417 bool savegame::is_illegal_file_char(char c)
418 {
419  return c == '/' || c == '\\' || c == ':' || (c >= 0x00 && c < 0x20)
420 #ifdef _WIN32
421  || c == '?' || c == '|' || c == '<' || c == '>' || c == '*' || c == '"'
422 #endif
423  ;
424 }
425 
426 std::string savegame::create_filename(unsigned int turn_number) const
427 {
428  std::string filename = create_initial_filename(turn_number);
429  filename.erase(std::remove_if(filename.begin(), filename.end(),
430  is_illegal_file_char), filename.end());
431  std::replace(filename.begin(), filename.end(), '_', ' ');
432  return filename;
433 }
434 
435 void savegame::before_save()
436 {
437 }
438 
439 bool savegame::save_game(const std::string& filename)
440 {
441 
442  try {
443  uint32_t start, end;
444  start = SDL_GetTicks();
445 
446  if (filename_.empty())
447  filename_ = filename;
448 
449  before_save();
450 
451  write_game_to_disk(filename_);
452  if (resources::persist != nullptr) {
455  }
456 
457  // Create an entry in the save_index. Doing this here ensures all leader image paths
458  // sre expanded in a context-independent fashion and can appear in the Load Game dialog
459  // even if a campaign-specific sprite is used. This is because the image's full path is
460  // only available if the binary-path context its a part of is loaded. Without this, if
461  // a player saves a game and exits the game or reloads the cache, the leader image will
462  // only be available within that specific binary context (when playing another game from
463  // the came campaign, for example).
465 
466  end = SDL_GetTicks();
467  LOG_SAVE << "Milliseconds to save " << filename_ << ": " << end - start << std::endl;
468 
469  if (show_confirmation_)
470  gui2::show_transient_message(_("Saved"), _("The game has been saved."));
471  return true;
472  } catch(const game::save_game_failed& e) {
473  ERR_SAVE << error_message_ << e.message << std::endl;
474 
475  gui2::show_error_message(error_message_ + e.message);
476  //do not bother retrying, since the user can just try to save the game again
477  //maybe show a yes-no dialog for "disable autosaves now"?
478 
479  return false;
480  };
481 }
482 
483 void savegame::write_game_to_disk(const std::string& filename)
484 {
485  LOG_SAVE << "savegame::save_game" << std::endl;
486 
487  filename_ = filename;
488  filename_ += compression::format_extension(compress_saves_);
489 
490  std::stringstream ss;
491  {
492  config_writer out(ss, compress_saves_);
493  write_game(out);
494  finish_save_game(out);
495  }
496  filesystem::scoped_ostream os(open_save_game(filename_));
497  (*os) << ss.str();
498 
499  if (!os->good()) {
500  throw game::save_game_failed(_("Could not write to file"));
501  }
502 }
503 
504 void savegame::write_game(config_writer &out)
505 {
506  log_scope("write_game");
507 
508  out.write_key_val("version", game_config::wesnoth_version.str());
509 
510  gamestate_.write_general_info(out);
511  out.open_child("statistics");
513  out.close_child("statistics");
514 }
515 
516 void savegame::finish_save_game(const config_writer &out)
517 {
518  try {
519  if(!out.good()) {
520  throw game::save_game_failed(_("Could not write to file"));
521  }
522  save_index_manager.remove(gamestate_.classification().label);
523  } catch(const filesystem::io_exception& e) {
524  throw game::save_game_failed(e.what());
525  }
526 }
527 
528 // Throws game::save_game_failed
529 filesystem::scoped_ostream savegame::open_save_game(const std::string &label)
530 {
531  try {
532  return filesystem::ostream_file(filesystem::get_saves_dir() + "/" + label);
533  } catch(const filesystem::io_exception& e) {
534  throw game::save_game_failed(e.what());
535  }
536 }
537 
539  : savegame(gamestate, compress_saves)
540 {
542 }
543 
544 std::string scenariostart_savegame::create_initial_filename(unsigned int) const
545 {
546  return gamestate().classification().label;
547 }
548 
551  gamestate().write_carryover(out);
552 }
553 
555  : savegame(gamestate, compress_saves, _("Save Replay"))
556 {}
557 
558 std::string replay_savegame::create_initial_filename(unsigned int) const
559 {
560  return formatter() << gamestate().classification().label << " " << _("replay");
561 }
562 
565 
566  gamestate().write_carryover(out);
567  out.write_child("replay_start", gamestate().replay_start());
568 
569  out.open_child("replay");
570  gamestate().get_replay().write(out);
571  out.close_child("replay");
572 
573 }
574 
576  : ingame_savegame(gamestate, compress_saves)
577 {
578  set_error_message(_("Could not auto save the game. Please save the game manually."));
579 }
580 
581 void autosave_savegame::autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
582 {
583  if(disable_autosave)
584  return;
585 
587 
588  remove_old_auto_saves(autosave_max, infinite_autosaves);
589 }
590 
591 std::string autosave_savegame::create_initial_filename(unsigned int turn_number) const
592 {
593  std::string filename;
594  if(gamestate().classification().label.empty())
595  filename = _("Auto-Save");
596  else
597  filename = gamestate().classification().label + "-" + _("Auto-Save") + std::to_string(turn_number);
598 
599  return filename;
600 }
601 
604  , ignore_(ignore)
605 {}
606 
607 int oos_savegame::show_save_dialog(const std::string& message, DIALOG_TYPE /*dialog_type*/)
608 {
609  int res = 0;
610 
611  if (!ignore_){
613  dlg.show();
614  res = dlg.get_retval();
615  }
616 
617  if (!check_filename(filename_)) {
618  res = gui2::retval::CANCEL;
619  }
620 
621  return res;
622 }
623 
625  : savegame(gamestate, compress_saves, _("Save Game"))
626 {
627 }
628 
629 std::string ingame_savegame::create_initial_filename(unsigned int turn_number) const
630 {
631  return formatter() << gamestate().classification().label
632  << " " << _("Turn") << " " << turn_number;
633 }
634 
636  log_scope("write_game");
637 
638  if(!gamestate().get_starting_point().validate_wml()) {
639  throw game::save_game_failed(_("Game state is corrupted"));
640  }
641 
643 
644  gamestate().write_carryover(out);
645  out.write_child("snapshot",gamestate().get_starting_point());
646  out.write_child("replay_start", gamestate().replay_start());
647  out.open_child("replay");
648  gamestate().get_replay().write(out);
649  out.close_child("replay");
650 }
651 
652 //changes done during 1.11.0-dev
654 {
655  if(!cfg.has_child("snapshot")){
656  return;
657  }
658 
659  const config& snapshot = cfg.child("snapshot");
660  const config& replay_start = cfg.child("replay_start");
661  const config& replay = cfg.child("replay");
662 
663  if(!cfg.has_child("carryover_sides") && !cfg.has_child("carryover_sides_start")){
665  //copy rng and menu items from toplevel to new carryover_sides
666  carryover["random_seed"] = cfg["random_seed"];
667  carryover["random_calls"] = cfg["random_calls"];
668  for(const config& menu_item : cfg.child_range("menu_item")) {
669  carryover.add_child("menu_item", menu_item);
670  }
671  carryover["difficulty"] = cfg["difficulty"];
672  carryover["random_mode"] = cfg["random_mode"];
673  //the scenario to be played is always stored as next_scenario in carryover_sides_start
674  carryover["next_scenario"] = cfg["scenario"];
675 
676  config carryover_start = carryover;
677 
678  //copy sides from either snapshot or replay_start to new carryover_sides
679  if(!snapshot.empty()){
680  for(const config& side : snapshot.child_range("side")) {
681  carryover.add_child("side", side);
682  }
683  //for compatibility with old savegames that use player instead of side
684  for(const config& side : snapshot.child_range("player")) {
685  carryover.add_child("side", side);
686  }
687  //save the sides from replay_start in carryover_sides_start
688  for(const config& side : replay_start.child_range("side")) {
689  carryover_start.add_child("side", side);
690  }
691  //for compatibility with old savegames that use player instead of side
692  for(const config& side : replay_start.child_range("player")) {
693  carryover_start.add_child("side", side);
694  }
695  } else if (!replay_start.empty()){
696  for(const config& side : replay_start.child_range("side")) {
697  carryover.add_child("side", side);
698  carryover_start.add_child("side", side);
699  }
700  //for compatibility with old savegames that use player instead of side
701  for(const config& side : replay_start.child_range("player")) {
702  carryover.add_child("side", side);
703  carryover_start.add_child("side", side);
704  }
705  }
706 
707  //get variables according to old hierarchy and copy them to new carryover_sides
708  if(!snapshot.empty()){
709  if(const config& variables_from_snapshot = snapshot.child("variables")){
710  carryover.add_child("variables", variables_from_snapshot);
711  carryover_start.add_child("variables", replay_start.child_or_empty("variables"));
712  } else if (const config& variables_from_cfg = cfg.child("variables")){
713  carryover.add_child("variables", variables_from_cfg);
714  carryover_start.add_child("variables", variables_from_cfg);
715  }
716  } else if (!replay_start.empty()){
717  if(const config& variables = replay_start.child("variables")){
718  carryover.add_child("variables", variables);
719  carryover_start.add_child("variables", variables);
720  }
721  } else {
722  carryover.add_child("variables", cfg.child("variables"));
723  carryover_start.add_child("variables", cfg.child("variables"));
724  }
725 
726  cfg.add_child("carryover_sides", carryover);
727  cfg.add_child("carryover_sides_start", carryover_start);
728  }
729 
730  //if replay and snapshot are empty we've got a start of scenario save and don't want replay_start either
731  if(replay.empty() && snapshot.empty()){
732  LOG_RG<<"removing replay_start \n";
733  cfg.clear_children("replay_start");
734  }
735 
736  //remove empty replay or snapshot so type of save can be detected more easily
737  if(replay.empty()){
738  LOG_RG<<"removing replay \n";
739  cfg.clear_children("replay");
740  }
741 
742  if(snapshot.empty()){
743  LOG_RG<<"removing snapshot \n";
744  cfg.clear_children("snapshot");
745  }
746 }
747 //changes done during 1.13.0-dev
749 {
750  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
751  {
752  if(!carryover_sides_start.has_attribute("next_underlying_unit_id"))
753  {
754  carryover_sides_start["next_underlying_unit_id"] = cfg["next_underlying_unit_id"];
755  }
756  }
757  if(cfg.child_or_empty("snapshot").empty())
758  {
759  cfg.clear_children("snapshot");
760  }
761  if(cfg.child_or_empty("replay_start").empty())
762  {
763  cfg.clear_children("replay_start");
764  }
765  if(config& snapshot = cfg.child("snapshot"))
766  {
767  //make [end_level] -> [end_level_data] since its alo called [end_level_data] in the carryover.
768  if(config& end_level = cfg.child("end_level") )
769  {
770  snapshot.add_child("end_level_data", end_level);
771  snapshot.clear_children("end_level");
772  }
773  //if we have a snapshot then we already applied carryover so there is no reason to keep this data.
774  if(cfg.has_child("carryover_sides_start"))
775  {
776  cfg.clear_children("carryover_sides_start");
777  }
778  }
779  if(!cfg.has_child("snapshot") && !cfg.has_child("replay_start"))
780  {
781  cfg.clear_children("carryover_sides");
782  }
783  //This code is needed because for example otherwise it won't find the (empty) era
784  if(!cfg.has_child("multiplayer")) {
785  cfg.add_child("multiplayer", config {
786  "mp_era", "era_blank",
787  "mp_use_map_settings", true,
788  });
789  }
790 }
791 
792 
793 //changes done during 1.13.0+dev
795 {
796  if(config& multiplayer = cfg.child("multiplayer")) {
797  if(multiplayer["mp_era"] == "era_blank") {
798  multiplayer["mp_era"] = "era_default";
799  }
800  }
801  //This currently only fixes start-of-scenario saves.
802  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
803  {
804  for(config& side : carryover_sides_start.child_range("side"))
805  {
806  for(config& unit : side.child_range("unit"))
807  {
808  if(config& modifications = unit.child("modifications"))
809  {
810  for(config& advancement : modifications.child_range("advance"))
811  {
812  modifications.add_child("advancement", advancement);
813  }
814  modifications.clear_children("advance");
815  }
816  }
817  }
818  }
819  for(config& snapshot : cfg.child_range("snapshot")) {
820  if (snapshot.has_attribute("used_items")) {
821  config used_items;
822  for(const std::string& item : utils::split(snapshot["used_items"])) {
823  used_items[item] = true;
824  }
825  snapshot.remove_attribute("used_items");
826  snapshot.add_child("used_items", used_items);
827  }
828  }
829 }
830 
832 {
833  version_info loaded_version(cfg["version"]);
834  if(loaded_version < version_info("1.12.0"))
835  {
837  }
838  // '<= version_info("1.13.0")' doesn't work
839  //because version_info cannot handle 1.13.0-dev versions correctly.
840  if(loaded_version < version_info("1.13.1"))
841  {
843  }
844  if(loaded_version <= version_info("1.13.1"))
845  {
847  }
848  LOG_RG<<"cfg after conversion "<<cfg<<"\n";
849 }
850 
851 }
oos_savegame(saved_game &gamestate, bool &ignore)
Definition: savegame.cpp:602
bool good() const
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
Remove autosaves that are no longer needed (according to the autosave policy in the preferences)...
Definition: save_index.cpp:311
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:150
bool load_game()
Load a game with pre-setting information for the load-game dialog.
Definition: savegame.cpp:158
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:423
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 ...
static void convert_old_saves_1_13_1(config &cfg)
Definition: savegame.cpp:794
void rebuild(const std::string &name)
Definition: save_index.cpp:44
void read_save_file(const std::string &name, config &cfg, std::string *error_log)
Read the complete config information out of a savefile.
Definition: save_index.cpp:270
std::map< std::string, t_string > string_map
void clear_children(T... keys)
Definition: config.hpp:477
std::string label
Name of the game (e.g.
std::string era()
Definition: game.cpp:699
This class represents a single unit of a specific type.
Definition: unit.hpp:99
std::string filename
Name of the savefile to be loaded.
Definition: savegame.hpp:40
game_classification * classification
Definition: resources.cpp:34
virtual void write_game(config_writer &out)
Writing the savegame config to a file.
Definition: savegame.cpp:504
static void convert_old_saves_1_13_0(config &cfg)
Definition: savegame.cpp:748
void set_gamestate()
Generate the gamestate out of the loaded game config.
Definition: savegame.cpp:262
replay_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:554
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:549
static bool file_exists(const fs::path &fpath)
Definition: filesystem.cpp:300
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:591
const std::string & filename() const
Definition: savegame.hpp:171
replay_recorder_base & get_replay()
Definition: saved_game.hpp:121
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:416
void remove(const std::string &name)
Definition: save_index.cpp:70
#define ERR_SAVE
Definition: savegame.cpp:53
void write_carryover(config_writer &out) const
Definition: saved_game.cpp:166
child_itors child_range(config_key_type key)
Definition: config.cpp:366
ingame_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:624
std::vector< save_info > get_saves_list(const std::string *dir, const std::string *filter)
Get a list of available saves.
Definition: save_index.cpp:190
Error used when game saving fails.
Definition: game_errors.hpp:38
autosave_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:575
load_game_metadata load_data_
Primary output information.
Definition: savegame.hpp:140
static CVideo & get_singleton()
Definition: video.hpp:48
Class for "normal" midgame saves.
Definition: savegame.hpp:242
persist_manager * persist
Definition: resources.cpp:26
bool confirm_load_save_from_different_version()
Definition: general.cpp:901
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
static bool execute(const config &cache_config, savegame::load_game_metadata &data)
Definition: game_load.hpp:37
bool show(const unsigned auto_close_time=0)
Shows the window.
std::string get_saves_dir()
void remove_attribute(config_key_type key)
Definition: config.cpp:239
-file util.hpp
scenariostart_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:538
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
std::string filename_
Definition: action_wml.cpp:555
void write_child(const std::string &key, const config &cfg)
const saved_game & gamestate() const
Definition: savegame.hpp:196
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
loadgame(const config &game_config, saved_game &gamestate)
Definition: savegame.cpp:80
void throw_quit_game_exception()
void write_key_val(const std::string &key, const T &value)
This template function will work with any type that can be assigned to an attribute_value.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:558
void close_child(const std::string &key)
This file contains the settings handling of the widget library.
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
Definition: version.cpp:151
std::ostringstream wrapper.
Definition: formatter.hpp:38
Class for writing a config out to a file in pieces.
bool disable_autosave
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
const version_info test_version("test")
Definition: version.hpp:212
void open_child(const std::string &key)
saved_game & gamestate_
Definition: savegame.hpp:138
void delete_game(const std::string &name)
Delete a savegame.
Definition: save_index.cpp:329
std::string create_filename() const
Build the filename according to the specific savegame&#39;s needs.
Definition: savegame.hpp:174
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
Definition: version.cpp:155
static bool is_replay_save(const config &cfg)
Definition: savegame.hpp:123
save_index_class save_index_manager
Definition: save_index.cpp:170
Modify, read and display user preferences.
void write(config_writer &out) const
Shows a yes and no button.
Definition: message.hpp:79
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:119
virtual int show_save_dialog(const std::string &message, DIALOG_TYPE dialog_type) override
Display the save game dialog.
Definition: savegame.cpp:607
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:629
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
const char * what() const noexcept
Definition: exceptions.hpp:37
void set_data(config &cfg)
destroys the passed config.
Definition: saved_game.cpp:676
const config & game_config_
Definition: savegame.hpp:136
#define LOG_SAVE
Definition: savegame.cpp:52
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:635
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:563
void convert_old_saves(config &cfg)
converts saves from older versions of wesnoth
Definition: savegame.cpp:831
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:40
std::string format_extension(format compression_format)
Definition: compression.hpp:26
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
Definition: savegame.hpp:74
config & get(const std::string &name)
Definition: save_index.cpp:82
std::size_t i
Definition: function.cpp:933
Thrown by operations encountering invalid UTF-8 data.
void clean_saves(const std::string &label)
Delete all autosaves of a certain scenario.
Definition: savegame.cpp:67
Game configuration data as global variables.
Definition: build_info.cpp:46
EXIT_STATUS start(const config &game_conf, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
An exception object used when an IO error occurs.
Definition: filesystem.hpp:48
bool check_filename(const std::string &filename)
Check, if the filename contains illegal constructs like ".gz".
Definition: savegame.cpp:406
std::string difficulty
The difficulty the save is meant to be loaded with.
Definition: savegame.hpp:43
bool is_compressed_file(const std::string &filename)
Definition: filesystem.hpp:230
#define log_scope(description)
Definition: log.hpp:186
#define LOG_RG
Definition: savegame.cpp:56
config summary
Summary config of the save selected in the load game dialog.
Definition: savegame.hpp:55
const version_info wesnoth_version(VERSION)
Definition: version.hpp:210
bool load_multiplayer_game()
Loading a game from within the multiplayer-create dialog.
Definition: savegame.cpp:267
Represents version numbers.
Definition: version.hpp:43
config & add_child(config_key_type key)
Definition: config.cpp:479
void copy_era(config &cfg)
Copy era information into the snapshot.
Definition: savegame.cpp:314
void set_error_message(const std::string &error_message)
Customize the standard error message.
Definition: savegame.hpp:193
compression::format save_compression_format()
Definition: game.cpp:872
static lg::log_domain log_enginerefac("enginerefac")
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
bool show_replay
State of the "show_replay" checkbox in the load-game dialog.
Definition: savegame.hpp:46
const std::vector< std::string > & modifications(bool mp)
Definition: game.cpp:729
game_classification & classification()
Definition: saved_game.hpp:55
static void convert_old_saves_1_11_0(config &cfg)
Definition: savegame.cpp:653
config write_stats()
Definition: statistics.cpp:607
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:581
std::string str() const
Serializes the version number into string form.
Definition: version.cpp:115
std::string message
Definition: exceptions.hpp:31
bool select_difficulty
State of the "change_difficulty" checkbox in the load-game dialog.
Definition: savegame.hpp:52
bool show_difficulty_dialog()
Display the difficulty dialog.
Definition: savegame.cpp:86
const std::string & title() const
Definition: savegame.hpp:195
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:203
std::string filename_
Filename of the savegame file on disk.
Definition: savegame.hpp:205
#define e
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:456
Dialog was closed with the OK button.
Definition: retval.hpp:34
bool save_game_exists(std::string name, compression::format compressed)
Returns true if there is already a savegame with that name.
Definition: savegame.cpp:61
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
mock_char c
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
Definition: version.hpp:211
savegame(saved_game &gamestate, const compression::format compress_saves, const std::string &title="Save")
The only constructor of savegame.
Definition: savegame.cpp:328
bool check_version_compatibility()
Call check_version_compatibility above, using the version of this savefile.
Definition: savegame.cpp:214
Interfaces for manipulating version numbers of engine, add-ons, etc.
static lg::log_domain log_engine("engine")
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:544
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
bool empty() const
Definition: config.cpp:837
bool save_game_automatic(bool ask_for_overwrite=false, const std::string &filename="")
Saves a game without user interaction, unless the file exists and it should be asked to overwrite it...
Definition: savegame.cpp:337
config load_config
Config information of the savefile to be loaded.
Definition: savegame.hpp:58
std::string version
Version game was created with.
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)
Definition: filesystem.cpp:932