48 #define LOG_SAVE LOG_STREAM(info, log_engine)
49 #define ERR_SAVE LOG_STREAM(err, log_engine)
52 #define LOG_RG LOG_STREAM(info, log_enginerefac)
65 const std::string prefix =
label +
"-" +
_(
"Auto-Save");
66 LOG_SAVE <<
"Cleaning saves with prefix '" << prefix <<
"'";
69 for(
const auto& save : manager->get_saves_list()) {
70 if(save.name().compare(0, prefix.length(), prefix) == 0) {
71 LOG_SAVE <<
"Deleting savegame '" << save.name() <<
"'";
72 manager->delete_game(save.name());
79 , gamestate_(gamestate)
93 if(campaign[
"id"] != campaign_id) {
100 if(!difficulty_dlg.
show()) {
137 ERR_SAVE <<
"Null pointer in save index";
147 if(summary[
"corrupt"].to_bool(
false)) {
161 bool skip_version_check =
true;
168 skip_version_check =
false;
183 ERR_SAVE <<
"Null pointer in save index";
187 std::string error_log;
193 side.remove_attribute(
"is_local");
196 if(!error_log.empty()) {
199 _(
"Warning: The file you have tried to load is corrupt. Loading anyway.\n") + error_log);
202 + std::string(
"(UTF-8 ERROR)"));
212 if(skip_version_check) {
244 const std::string message
245 =
_(
"This save is from an old, unsupported version ($version_number|) and cannot be loaded.");
247 symbols[
"version_number"] = save_version.
str();
252 if(
prefs::get().confirm_load_save_from_different_version()) {
253 const std::string message
254 =
_(
"This save is from a different version of the game ($version_number|), and might not work with this "
257 "<b>Warning:</b> saves in the middle of campaigns are especially likely to fail, and you should either "
258 "use the old version or restart the campaign. Even when a saved game seems to load successfully, "
259 "subtler aspects like gameplay balance and story progression could be impacted. The difficulty, the "
260 "challenge, the <i>fun</i> may be missing.\n"
262 "For example, the campaign may have been rebalanced with fewer enemies in the early scenarios, but "
263 "expecting your recall list to have correspondingly less experience in the late scenarios.\n"
265 "Do you wish to continue?");
267 symbols[
"version_number"] = save_version.
str();
293 ERR_SAVE <<
"Null pointer in save index";
299 std::string error_log;
308 if(!error_log.empty()) {
337 auto era = replay_start->optional_child(
"era");
347 snapshot->add_child(
"era", *era);
354 , gamestate_(gamestate)
355 , error_message_(
_(
"The game could not be saved: "))
356 , show_confirmation_(false)
357 , compress_saves_(compress_saves)
361 bool savegame::save_game_automatic(
bool ask_for_overwrite,
const std::string&
filename)
369 if(ask_for_overwrite) {
370 if(!check_overwrite()) {
371 return save_game_interactive(
"", savegame::OK_CANCEL);
378 bool savegame::save_game_interactive(
const std::string& message,
DIALOG_TYPE dialog_type)
380 show_confirmation_ =
true;
383 const int res = show_save_dialog(message, dialog_type);
396 int savegame::show_save_dialog(
const std::string& message,
DIALOG_TYPE dialog_type)
400 if(dialog_type == OK_CANCEL) {
404 }
else if(dialog_type == YES_NO) {
417 bool savegame::check_overwrite()
423 std::ostringstream message;
424 message <<
_(
"Save already exists. Do you want to overwrite it?") <<
"\n" <<
_(
"Name: ") <<
filename_;
429 bool savegame::check_filename(
const std::string&
filename)
437 gui2::show_error_message(
_(
"Save names may not end with a dot, or contain two dots or any of the following characters:\n \" * / : < > ? \\ | ~"));
444 std::string savegame::create_filename(
unsigned int turn_number)
const
446 return create_initial_filename(turn_number);
449 void savegame::before_save()
453 bool savegame::save_game(
const std::string&
filename)
456 utils::optional<const utils::ms_optimer> timer([
this](
const auto& timer) {
484 if(show_confirmation_) {
499 void savegame::write_game_to_disk(
const std::string&
filename)
506 std::stringstream ss;
510 finish_save_game(out);
527 gamestate_.write_general_info(out);
552 :
savegame(gamestate, compress_saves)
569 :
savegame(gamestate, compress_saves,
_(
"Save Replay"))
575 time_t
t = std::time(
nullptr);
576 tm tm = *std::localtime(&
t);
577 auto time = std::put_time(&tm,
"%Y%m%d-%H%M%S");
609 manager->delete_old_auto_saves(autosave_max, infinite_autosaves);
648 :
savegame(gamestate, compress_saves,
_(
"Save Game"))
661 if(!
gamestate().get_starting_point().validate_wml()) {
689 carryover[
"random_seed"] = cfg[
"random_seed"];
690 carryover[
"random_calls"] = cfg[
"random_calls"];
693 carryover.add_child(
"menu_item", menu_item);
696 carryover[
"difficulty"] = cfg[
"difficulty"];
697 carryover[
"random_mode"] = cfg[
"random_mode"];
699 carryover[
"next_scenario"] = cfg[
"scenario"];
704 if(!snapshot.
empty()) {
720 }
else if(!replay_start.
empty()) {
733 if(!snapshot.
empty()) {
734 if(
auto variables_from_snapshot = snapshot.
optional_child(
"variables")) {
735 carryover.add_child(
"variables", *variables_from_snapshot);
737 }
else if(
auto variables_from_cfg = cfg.
optional_child(
"variables")) {
738 carryover.add_child(
"variables", *variables_from_cfg);
739 carryover_start.
add_child(
"variables", *variables_from_cfg);
741 }
else if(!replay_start.
empty()) {
743 carryover.add_child(
"variables", *variables);
744 carryover_start.
add_child(
"variables", *variables);
752 cfg.
add_child(
"carryover_sides_start", carryover_start);
757 LOG_RG <<
"removing replay_start";
763 LOG_RG <<
"removing replay";
767 if(snapshot.
empty()) {
768 LOG_RG <<
"removing snapshot";
775 if(
auto carryover_sides_start = cfg.
optional_child(
"carryover_sides_start")) {
776 if(!carryover_sides_start->has_attribute(
"next_underlying_unit_id")) {
777 carryover_sides_start[
"next_underlying_unit_id"] = cfg[
"next_underlying_unit_id"];
792 snapshot->add_child(
"end_level_data", *end_level);
793 snapshot->clear_children(
"end_level");
796 if(cfg.
has_child(
"carryover_sides_start")) {
811 "mp_use_map_settings",
821 if(multiplayer[
"mp_era"] ==
"era_blank") {
822 multiplayer[
"mp_era"] =
"era_default";
827 if(
auto carryover_sides_start = cfg.
optional_child(
"carryover_sides_start")) {
829 for(
config&
unit : side.child_range(
"unit")) {
830 if(
auto modifications =
unit.optional_child(
"modifications")) {
832 modifications->add_child(
"advancement", advancement);
834 modifications->clear_children(
"advance");
841 if(snapshot.has_attribute(
"used_items")) {
843 for(
const std::string& item :
utils::split(snapshot[
"used_items"])) {
844 used_items[item] =
true;
848 snapshot.add_child(
"used_items", used_items);
856 if(cfg[
"era_id"].empty()) {
860 if(cfg[
"active_mods"].empty()) {
861 cfg[
"active_mods"] = cfg.
child_or_empty(
"multiplayer")[
"active_mods"];
886 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)
Equivalent 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
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)
@ 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)
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.
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")
std::string filename
Filename.
An exception object used when an IO error occurs.
Error used when game saving fails.