16 #include <boost/iostreams/filter/gzip.hpp>
53 #define LOG_SAVE LOG_STREAM(info, log_engine)
54 #define ERR_SAVE LOG_STREAM(err, log_engine)
57 #define LOG_RG LOG_STREAM(info, log_enginerefac)
70 const std::string prefix =
label +
"-" +
_(
"Auto-Save");
71 LOG_SAVE <<
"Cleaning saves with prefix '" << prefix <<
"'";
74 for(
const auto& save : manager->get_saves_list()) {
75 if(save.name().compare(0, prefix.length(), prefix) == 0) {
76 LOG_SAVE <<
"Deleting savegame '" << save.name() <<
"'";
77 manager->delete_game(save.name());
84 , gamestate_(gamestate)
98 if(campaign[
"id"] != campaign_id) {
105 if(!difficulty_dlg.
show()) {
142 ERR_SAVE <<
"Null pointer in save index";
152 if(summary[
"corrupt"].to_bool(
false)) {
166 bool skip_version_check =
true;
173 skip_version_check =
false;
188 ERR_SAVE <<
"Null pointer in save index";
192 std::string error_log;
198 side.remove_attribute(
"is_local");
201 if(!error_log.empty()) {
204 _(
"Warning: The file you have tried to load is corrupt. Loading anyway.\n") + error_log);
207 + std::string(
"(UTF-8 ERROR)"));
217 if(skip_version_check) {
249 const std::string message
250 =
_(
"This save is from an old, unsupported version ($version_number|) and cannot be loaded.");
252 symbols[
"version_number"] = save_version.
str();
258 const std::string message
259 =
_(
"This save is from a different version of the game ($version_number|), and might not work with this "
262 "<b>Warning:</b> saves in the middle of campaigns are especially likely to fail, and you should either "
263 "use the old version or restart the campaign. Even when a saved game seems to load successfully, "
264 "subtler aspects like gameplay balance and story progression could be impacted. The difficulty, the "
265 "challenge, the <i>fun</i> may be missing.\n"
267 "For example, the campaign may have been rebalanced with fewer enemies in the early scenarios, but "
268 "expecting your recall list to have correspondingly less experience in the late scenarios.\n"
270 "Do you wish to continue?");
272 symbols[
"version_number"] = save_version.
str();
298 ERR_SAVE <<
"Null pointer in save index";
304 std::string error_log;
313 if(!error_log.empty()) {
342 auto era = replay_start->optional_child(
"era");
352 snapshot->add_child(
"era", *
era);
359 , gamestate_(gamestate)
360 , error_message_(
_(
"The game could not be saved: "))
361 , show_confirmation_(false)
362 , compress_saves_(compress_saves)
366 bool savegame::save_game_automatic(
bool ask_for_overwrite,
const std::string& filename)
368 if(filename.empty()) {
374 if(ask_for_overwrite) {
375 if(!check_overwrite()) {
376 return save_game_interactive(
"", savegame::OK_CANCEL);
383 bool savegame::save_game_interactive(
const std::string& message,
DIALOG_TYPE dialog_type)
385 show_confirmation_ =
true;
388 const int res = show_save_dialog(message, dialog_type);
401 int savegame::show_save_dialog(
const std::string& message,
DIALOG_TYPE dialog_type)
405 if(dialog_type == OK_CANCEL) {
409 }
else if(dialog_type == YES_NO) {
422 bool savegame::check_overwrite()
428 std::ostringstream message;
429 message <<
_(
"Save already exists. Do you want to overwrite it?") <<
"\n" <<
_(
"Name: ") <<
filename_;
434 bool savegame::check_filename(
const std::string& filename)
442 gui2::show_error_message(
_(
"Save names may not end with a dot, or contain two dots or any of the following characters:\n \" * / : < > ? \\ | ~"));
449 std::string savegame::create_filename(
unsigned int turn_number)
const
451 return create_initial_filename(turn_number);
454 void savegame::before_save()
458 bool savegame::save_game(
const std::string& filename)
462 start = SDL_GetTicks();
485 end = SDL_GetTicks();
488 if(show_confirmation_) {
503 void savegame::write_game_to_disk(
const std::string& filename)
510 std::stringstream ss;
514 finish_save_game(out);
531 gamestate_.write_general_info(out);
556 :
savegame(gamestate, compress_saves)
573 :
savegame(gamestate, compress_saves,
_(
"Save Replay"))
579 time_t
t = std::time(
nullptr);
580 tm tm = *std::localtime(&
t);
581 auto time = std::put_time(&tm,
"%Y%m%d-%H%M%S");
613 manager->delete_old_auto_saves(autosave_max, infinite_autosaves);
652 :
savegame(gamestate, compress_saves,
_(
"Save Game"))
665 if(!
gamestate().get_starting_point().validate_wml()) {
693 carryover[
"random_seed"] = cfg[
"random_seed"];
694 carryover[
"random_calls"] = cfg[
"random_calls"];
697 carryover.add_child(
"menu_item", menu_item);
700 carryover[
"difficulty"] = cfg[
"difficulty"];
701 carryover[
"random_mode"] = cfg[
"random_mode"];
703 carryover[
"next_scenario"] = cfg[
"scenario"];
708 if(!snapshot.
empty()) {
724 }
else if(!replay_start.
empty()) {
737 if(!snapshot.
empty()) {
738 if(
auto variables_from_snapshot = snapshot.
optional_child(
"variables")) {
739 carryover.add_child(
"variables", *variables_from_snapshot);
741 }
else if(
auto variables_from_cfg = cfg.
optional_child(
"variables")) {
742 carryover.add_child(
"variables", *variables_from_cfg);
743 carryover_start.
add_child(
"variables", *variables_from_cfg);
745 }
else if(!replay_start.
empty()) {
747 carryover.add_child(
"variables", *variables);
748 carryover_start.
add_child(
"variables", *variables);
756 cfg.
add_child(
"carryover_sides_start", carryover_start);
761 LOG_RG <<
"removing replay_start";
767 LOG_RG <<
"removing replay";
771 if(snapshot.
empty()) {
772 LOG_RG <<
"removing snapshot";
779 if(
auto carryover_sides_start = cfg.
optional_child(
"carryover_sides_start")) {
780 if(!carryover_sides_start->has_attribute(
"next_underlying_unit_id")) {
781 carryover_sides_start[
"next_underlying_unit_id"] = cfg[
"next_underlying_unit_id"];
796 snapshot->add_child(
"end_level_data", *end_level);
797 snapshot->clear_children(
"end_level");
800 if(cfg.
has_child(
"carryover_sides_start")) {
815 "mp_use_map_settings",
825 if(multiplayer[
"mp_era"] ==
"era_blank") {
826 multiplayer[
"mp_era"] =
"era_default";
831 if(
auto carryover_sides_start = cfg.
optional_child(
"carryover_sides_start")) {
833 for(
config&
unit : side.child_range(
"unit")) {
845 if(snapshot.has_attribute(
"used_items")) {
848 used_items[
item] =
true;
852 snapshot.add_child(
"used_items", used_items);
860 if(cfg[
"era_id"].empty()) {
864 if(cfg[
"active_mods"].empty()) {
865 cfg[
"active_mods"] = cfg.
child_or_empty(
"multiplayer")[
"active_mods"];
890 LOG_RG <<
"cfg after conversion " << cfg;
Class for writing a config out to a file in pieces.
void close_child(const std::string &key)
void write_child(const std::string &key, const config &cfg)
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.
void open_child(const std::string &key)
A config object defines a single node in a WML file, with access to child nodes.
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.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
void clear_children(T... keys)
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
child_itors child_range(config_key_type key)
void remove_attribute(config_key_type key)
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Euivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
std::string version
Version game was created with.
std::string label
Name of the game (e.g.
config_array_view child_range(config_key_type key) const
The campaign mode difficulty menu.
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
static bool execute(const game_config_view &cache_config, savegame::load_game_metadata &data)
This shows the dialog to create a savegame file.
@ yes_no_buttons
Shows a yes and no button.
bool show(const unsigned auto_close_time=0)
Shows the window.
int get_retval() const
Returns the cached window exit code.
void write(config_writer &out) const
game_classification & classification()
replay_recorder_base & get_replay()
void set_data(config &cfg)
destroys the passed config.
void write_carryover(config_writer &out) const
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
autosave_savegame(saved_game &gamestate, const compression::format compress_saves)
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Class for "normal" midgame saves.
ingame_savegame(saved_game &gamestate, const compression::format compress_saves)
void write_game(config_writer &out) override
Writing the savegame config to a file.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
void set_gamestate()
Generate the gamestate out of the loaded game config.
void copy_era(config &cfg)
Copy era information into the snapshot.
bool check_version_compatibility()
Call check_version_compatibility above, using the version of this savefile.
bool load_game_ingame()
Load a game without providing any information.
loadgame(const std::shared_ptr< save_index_class > &index, saved_game &gamestate)
static bool is_replay_save(const config &cfg)
load_game_metadata load_data_
Primary output information.
bool load_multiplayer_game()
Loading a game from within the multiplayer-create dialog.
bool show_difficulty_dialog()
Display the difficulty dialog.
bool load_game()
Load a game with pre-setting information for the load-game dialog.
const game_config_view & game_config_
oos_savegame(saved_game &gamestate, bool &ignore)
virtual int show_save_dialog(const std::string &message, DIALOG_TYPE dialog_type) override
Display the save game dialog.
void write_game(config_writer &out) override
Writing the savegame config to a file.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
replay_savegame(saved_game &gamestate, const compression::format compress_saves)
static std::shared_ptr< save_index_class > default_saves_dir()
Returns an instance for managing saves in filesystem::get_saves_dir()
The base class for all savegame stuff.
bool check_filename(const std::string &filename)
Check, if the filename contains illegal constructs like ".gz".
std::string filename_
Filename of the savegame file on disk.
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.
virtual void write_game(config_writer &out)
Writing the savegame config to a file.
std::string create_filename() const
Build the filename according to the specific savegame's needs.
const std::string & title() const
const std::string & filename() const
void set_error_message(const std::string &error_message)
Customize the standard error message.
const saved_game & gamestate() const
scenariostart_savegame(saved_game &gamestate, const compression::format compress_saves)
void write_game(config_writer &out) override
Writing the savegame config to a file.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
This class represents a single unit of a specific type.
Thrown by operations encountering invalid UTF-8 data.
Represents version numbers.
std::string str() const
Serializes the version number into string form.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
Contains the exception interfaces used to signal completion of a scenario, campaign or turn.
void throw_quit_game_exception()
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
std::string label
What to show in the filter's drop-down list.
Standard logging facilities (interface).
#define log_scope(description)
std::string format_extension(format compression_format)
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.
static bool file_exists(const bfs::path &fpath)
bool is_legal_user_file_name(const std::string &name, bool allow_whitespace=true)
Returns whether the given filename is a legal name for a user-created file.
bool is_compressed_file(const std::string &filename)
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::unique_ptr< std::ostream > scoped_ostream
Game configuration data as global variables.
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
const version_info test_version("test")
const version_info wesnoth_version(VERSION)
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.
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.
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
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.
@ OK
Dialog was closed with the OK button.
@ CANCEL
Dialog was closed with the CANCEL button.
std::pair< std::string, unsigned > item
Modify, read and display user preferences.
compression::format save_compression_format()
bool confirm_load_save_from_different_version()
const std::vector< std::string > & modifications(bool mp)
persist_manager * persist
game_classification * classification
void clean_saves(const std::string &label)
Delete all autosaves of a certain scenario from the default save directory.
static void convert_old_saves_1_13_0(config &cfg)
bool save_game_exists(std::string name, compression::format compressed)
Returns true if there is already a savegame with this name, looking only in the default save director...
void convert_old_saves(config &cfg)
converts saves from older versions of wesnoth
static void convert_old_saves_1_11_0(config &cfg)
static void convert_old_saves_1_13_1(config &cfg)
void read_save_file(const std::string &dir, const std::string &name, config &cfg, std::string *error_log)
Read the complete config information out of a savefile.
static void convert_old_saves_1_15_3(config &cfg)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
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 ...
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
bool headless()
The game is running headless.
static lg::log_domain log_engine("engine")
static lg::log_domain log_enginerefac("enginerefac")
This file contains the settings handling of the widget library.
An exception object used when an IO error occurs.
Error used when game saving fails.