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