The Battle for Wesnoth  1.15.1+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 https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include <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 "game_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  const std::string prefix = label + "-" + _("Auto-Save");
70  LOG_SAVE << "Cleaning saves with prefix '" << prefix << "'\n";
71 
72  for(const auto& save : get_saves_list()) {
73  if(save.name().compare(0, prefix.length(), prefix) == 0) {
74  LOG_SAVE << "Deleting savegame '" << save.name() << "'\n";
75  delete_game(save.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.show()) {
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 std::string savegame::create_filename(unsigned int turn_number) const
418 {
419  return create_initial_filename(turn_number);
420 }
421 
422 void savegame::before_save()
423 {
424 }
425 
426 bool savegame::save_game(const std::string& filename)
427 {
428 
429  try {
430  uint32_t start, end;
431  start = SDL_GetTicks();
432 
433  if (filename_.empty())
434  filename_ = filename;
435 
436  before_save();
437 
438  write_game_to_disk(filename_);
439  if (resources::persist != nullptr) {
442  }
443 
444  // Create an entry in the save_index. Doing this here ensures all leader image paths
445  // sre expanded in a context-independent fashion and can appear in the Load Game dialog
446  // even if a campaign-specific sprite is used. This is because the image's full path is
447  // only available if the binary-path context its a part of is loaded. Without this, if
448  // a player saves a game and exits the game or reloads the cache, the leader image will
449  // only be available within that specific binary context (when playing another game from
450  // the came campaign, for example).
452 
453  end = SDL_GetTicks();
454  LOG_SAVE << "Milliseconds to save " << filename_ << ": " << end - start << std::endl;
455 
456  if (show_confirmation_)
457  gui2::show_transient_message(_("Saved"), _("The game has been saved."));
458  return true;
459  } catch(const game::save_game_failed& e) {
460  ERR_SAVE << error_message_ << e.message << std::endl;
461 
462  gui2::show_error_message(error_message_ + e.message);
463  //do not bother retrying, since the user can just try to save the game again
464  //maybe show a yes-no dialog for "disable autosaves now"?
465 
466  return false;
467  };
468 }
469 
470 void savegame::write_game_to_disk(const std::string& filename)
471 {
472  LOG_SAVE << "savegame::save_game" << std::endl;
473 
474  filename_ = filename;
475  filename_ += compression::format_extension(compress_saves_);
476 
477  std::stringstream ss;
478  {
479  config_writer out(ss, compress_saves_);
480  write_game(out);
481  finish_save_game(out);
482  }
483  filesystem::scoped_ostream os(open_save_game(filename_));
484  (*os) << ss.str();
485 
486  if (!os->good()) {
487  throw game::save_game_failed(_("Could not write to file"));
488  }
489 }
490 
491 void savegame::write_game(config_writer &out)
492 {
493  log_scope("write_game");
494 
495  out.write_key_val("version", game_config::wesnoth_version.str());
496 
497  gamestate_.write_general_info(out);
498  out.open_child("statistics");
500  out.close_child("statistics");
501 }
502 
503 void savegame::finish_save_game(const config_writer &out)
504 {
505  try {
506  if(!out.good()) {
507  throw game::save_game_failed(_("Could not write to file"));
508  }
509  save_index_manager.remove(gamestate_.classification().label);
510  } catch(const filesystem::io_exception& e) {
511  throw game::save_game_failed(e.what());
512  }
513 }
514 
515 // Throws game::save_game_failed
516 filesystem::scoped_ostream savegame::open_save_game(const std::string &label)
517 {
518  try {
519  return filesystem::ostream_file(filesystem::get_saves_dir() + "/" + label);
520  } catch(const filesystem::io_exception& e) {
521  throw game::save_game_failed(e.what());
522  }
523 }
524 
526  : savegame(gamestate, compress_saves)
527 {
529 }
530 
531 std::string scenariostart_savegame::create_initial_filename(unsigned int) const
532 {
533  return gamestate().classification().label;
534 }
535 
538  gamestate().write_carryover(out);
539 }
540 
542  : savegame(gamestate, compress_saves, _("Save Replay"))
543 {}
544 
545 std::string replay_savegame::create_initial_filename(unsigned int) const
546 {
547  return formatter() << gamestate().classification().label << " " << _("replay");
548 }
549 
552 
553  gamestate().write_carryover(out);
554  out.write_child("replay_start", gamestate().replay_start());
555 
556  out.open_child("replay");
557  gamestate().get_replay().write(out);
558  out.close_child("replay");
559 
560 }
561 
563  : ingame_savegame(gamestate, compress_saves)
564 {
565  set_error_message(_("Could not auto save the game. Please save the game manually."));
566 }
567 
568 void autosave_savegame::autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
569 {
570  if(disable_autosave)
571  return;
572 
574 
575  remove_old_auto_saves(autosave_max, infinite_autosaves);
576 }
577 
578 std::string autosave_savegame::create_initial_filename(unsigned int turn_number) const
579 {
580  std::string filename;
581  if(gamestate().classification().label.empty())
582  filename = _("Auto-Save");
583  else
584  filename = gamestate().classification().label + "-" + _("Auto-Save") + std::to_string(turn_number);
585 
586  return filename;
587 }
588 
591  , ignore_(ignore)
592 {}
593 
594 int oos_savegame::show_save_dialog(const std::string& message, DIALOG_TYPE /*dialog_type*/)
595 {
596  int res = 0;
597 
598  if (!ignore_){
600  dlg.show();
601  res = dlg.get_retval();
602  }
603 
604  if (!check_filename(filename_)) {
605  res = gui2::retval::CANCEL;
606  }
607 
608  return res;
609 }
610 
612  : savegame(gamestate, compress_saves, _("Save Game"))
613 {
614 }
615 
616 std::string ingame_savegame::create_initial_filename(unsigned int turn_number) const
617 {
618  return formatter() << gamestate().classification().label
619  << " " << _("Turn") << " " << turn_number;
620 }
621 
623  log_scope("write_game");
624 
625  if(!gamestate().get_starting_point().validate_wml()) {
626  throw game::save_game_failed(_("Game state is corrupted"));
627  }
628 
630 
631  gamestate().write_carryover(out);
632  out.write_child("snapshot",gamestate().get_starting_point());
633  out.write_child("replay_start", gamestate().replay_start());
634  out.open_child("replay");
635  gamestate().get_replay().write(out);
636  out.close_child("replay");
637 }
638 
639 //changes done during 1.11.0-dev
641 {
642  if(!cfg.has_child("snapshot")){
643  return;
644  }
645 
646  const config& snapshot = cfg.child("snapshot");
647  const config& replay_start = cfg.child("replay_start");
648  const config& replay = cfg.child("replay");
649 
650  if(!cfg.has_child("carryover_sides") && !cfg.has_child("carryover_sides_start")){
652  //copy rng and menu items from toplevel to new carryover_sides
653  carryover["random_seed"] = cfg["random_seed"];
654  carryover["random_calls"] = cfg["random_calls"];
655  for(const config& menu_item : cfg.child_range("menu_item")) {
656  carryover.add_child("menu_item", menu_item);
657  }
658  carryover["difficulty"] = cfg["difficulty"];
659  carryover["random_mode"] = cfg["random_mode"];
660  //the scenario to be played is always stored as next_scenario in carryover_sides_start
661  carryover["next_scenario"] = cfg["scenario"];
662 
663  config carryover_start = carryover;
664 
665  //copy sides from either snapshot or replay_start to new carryover_sides
666  if(!snapshot.empty()){
667  for(const config& side : snapshot.child_range("side")) {
668  carryover.add_child("side", side);
669  }
670  //for compatibility with old savegames that use player instead of side
671  for(const config& side : snapshot.child_range("player")) {
672  carryover.add_child("side", side);
673  }
674  //save the sides from replay_start in carryover_sides_start
675  for(const config& side : replay_start.child_range("side")) {
676  carryover_start.add_child("side", side);
677  }
678  //for compatibility with old savegames that use player instead of side
679  for(const config& side : replay_start.child_range("player")) {
680  carryover_start.add_child("side", side);
681  }
682  } else if (!replay_start.empty()){
683  for(const config& side : replay_start.child_range("side")) {
684  carryover.add_child("side", side);
685  carryover_start.add_child("side", side);
686  }
687  //for compatibility with old savegames that use player instead of side
688  for(const config& side : replay_start.child_range("player")) {
689  carryover.add_child("side", side);
690  carryover_start.add_child("side", side);
691  }
692  }
693 
694  //get variables according to old hierarchy and copy them to new carryover_sides
695  if(!snapshot.empty()){
696  if(const config& variables_from_snapshot = snapshot.child("variables")){
697  carryover.add_child("variables", variables_from_snapshot);
698  carryover_start.add_child("variables", replay_start.child_or_empty("variables"));
699  } else if (const config& variables_from_cfg = cfg.child("variables")){
700  carryover.add_child("variables", variables_from_cfg);
701  carryover_start.add_child("variables", variables_from_cfg);
702  }
703  } else if (!replay_start.empty()){
704  if(const config& variables = replay_start.child("variables")){
705  carryover.add_child("variables", variables);
706  carryover_start.add_child("variables", variables);
707  }
708  } else {
709  carryover.add_child("variables", cfg.child("variables"));
710  carryover_start.add_child("variables", cfg.child("variables"));
711  }
712 
713  cfg.add_child("carryover_sides", carryover);
714  cfg.add_child("carryover_sides_start", carryover_start);
715  }
716 
717  //if replay and snapshot are empty we've got a start of scenario save and don't want replay_start either
718  if(replay.empty() && snapshot.empty()){
719  LOG_RG<<"removing replay_start \n";
720  cfg.clear_children("replay_start");
721  }
722 
723  //remove empty replay or snapshot so type of save can be detected more easily
724  if(replay.empty()){
725  LOG_RG<<"removing replay \n";
726  cfg.clear_children("replay");
727  }
728 
729  if(snapshot.empty()){
730  LOG_RG<<"removing snapshot \n";
731  cfg.clear_children("snapshot");
732  }
733 }
734 //changes done during 1.13.0-dev
736 {
737  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
738  {
739  if(!carryover_sides_start.has_attribute("next_underlying_unit_id"))
740  {
741  carryover_sides_start["next_underlying_unit_id"] = cfg["next_underlying_unit_id"];
742  }
743  }
744  if(cfg.child_or_empty("snapshot").empty())
745  {
746  cfg.clear_children("snapshot");
747  }
748  if(cfg.child_or_empty("replay_start").empty())
749  {
750  cfg.clear_children("replay_start");
751  }
752  if(config& snapshot = cfg.child("snapshot"))
753  {
754  //make [end_level] -> [end_level_data] since its alo called [end_level_data] in the carryover.
755  if(config& end_level = cfg.child("end_level") )
756  {
757  snapshot.add_child("end_level_data", end_level);
758  snapshot.clear_children("end_level");
759  }
760  //if we have a snapshot then we already applied carryover so there is no reason to keep this data.
761  if(cfg.has_child("carryover_sides_start"))
762  {
763  cfg.clear_children("carryover_sides_start");
764  }
765  }
766  if(!cfg.has_child("snapshot") && !cfg.has_child("replay_start"))
767  {
768  cfg.clear_children("carryover_sides");
769  }
770  //This code is needed because for example otherwise it won't find the (empty) era
771  if(!cfg.has_child("multiplayer")) {
772  cfg.add_child("multiplayer", config {
773  "mp_era", "era_blank",
774  "mp_use_map_settings", true,
775  });
776  }
777 }
778 
779 
780 //changes done during 1.13.0+dev
782 {
783  if(config& multiplayer = cfg.child("multiplayer")) {
784  if(multiplayer["mp_era"] == "era_blank") {
785  multiplayer["mp_era"] = "era_default";
786  }
787  }
788  //This currently only fixes start-of-scenario saves.
789  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
790  {
791  for(config& side : carryover_sides_start.child_range("side"))
792  {
793  for(config& unit : side.child_range("unit"))
794  {
795  if(config& modifications = unit.child("modifications"))
796  {
797  for(config& advancement : modifications.child_range("advance"))
798  {
799  modifications.add_child("advancement", advancement);
800  }
801  modifications.clear_children("advance");
802  }
803  }
804  }
805  }
806  for(config& snapshot : cfg.child_range("snapshot")) {
807  if (snapshot.has_attribute("used_items")) {
808  config used_items;
809  for(const std::string& item : utils::split(snapshot["used_items"])) {
810  used_items[item] = true;
811  }
812  snapshot.remove_attribute("used_items");
813  snapshot.add_child("used_items", used_items);
814  }
815  }
816 }
817 
819 {
820  version_info loaded_version(cfg["version"]);
821  if(loaded_version < version_info("1.12.0"))
822  {
824  }
825  // '<= version_info("1.13.0")' doesn't work
826  //because version_info cannot handle 1.13.0-dev versions correctly.
827  if(loaded_version < version_info("1.13.1"))
828  {
830  }
831  if(loaded_version <= version_info("1.13.1"))
832  {
834  }
835  LOG_RG<<"cfg after conversion "<<cfg<<"\n";
836 }
837 
838 }
oos_savegame(saved_game &gamestate, bool &ignore)
Definition: savegame.cpp:589
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:152
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:420
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:781
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:509
std::string label
Name of the game (e.g.
std::string era()
Definition: game.cpp:712
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
Interfaces for manipulating version numbers of engine, add-ons, etc.
game_classification * classification
Definition: resources.cpp:34
virtual void write_game(config_writer &out)
Writing the savegame config to a file.
Definition: savegame.cpp:491
static void convert_old_saves_1_13_0(config &cfg)
Definition: savegame.cpp:735
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:541
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:536
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:578
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:412
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:204
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:282
child_itors child_range(config_key_type key)
Definition: config.cpp:362
ingame_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:611
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
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, const bool restore_background)
Shows a transient message to the user.
Error used when game saving fails.
Definition: game_errors.hpp:38
autosave_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:562
load_game_metadata load_data_
Primary output information.
Definition: savegame.hpp:140
static CVideo & get_singleton()
Definition: video.hpp:43
Class for "normal" midgame saves.
Definition: savegame.hpp:239
persist_manager * persist
Definition: resources.cpp:26
bool confirm_load_save_from_different_version()
Definition: general.cpp:1037
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:235
-file util.hpp
scenariostart_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:525
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)
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
const saved_game & gamestate() const
Definition: savegame.hpp:196
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
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:545
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").
std::ostringstream wrapper.
Definition: formatter.hpp:38
Class for writing a config out to a file in pieces.
bool disable_autosave
const version_info test_version("test")
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").
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:594
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:616
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:697
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:622
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:550
void convert_old_saves(config &cfg)
converts saves from older versions of wesnoth
Definition: savegame.cpp:818
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
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:49
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
static void save(LexState *ls, int c)
Definition: llex.cpp:57
const version_info wesnoth_version(VERSION)
bool load_multiplayer_game()
Loading a game from within the multiplayer-create dialog.
Definition: savegame.cpp:267
Represents version numbers.
config & add_child(config_key_type key)
Definition: config.cpp:476
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:885
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:742
game_classification & classification()
Definition: saved_game.hpp:55
static void convert_old_saves_1_11_0(config &cfg)
Definition: savegame.cpp:640
config write_stats()
Definition: statistics.cpp:746
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:568
std::string str() const
Serializes the version number into string form.
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
EXIT_STATUS start(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
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:205
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:453
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:92
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
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
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:531
bool empty() const
Definition: config.cpp:884
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
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
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:958