Fixed a bunch of issues with game loading

* If no game was show in the dialog (due to an invalid filter) one could still use Enter to load a game
* In the same situation above, ESC would cause a crash
* Canceling the Select Difficulty dialog would still try to load a game
  This might have been the intended behavior, but it's not optimal.
This commit is contained in:
Charles Dang 2016-09-08 07:50:51 +11:00
parent 9ea794e5a4
commit a0ad80299b
4 changed files with 123 additions and 160 deletions

View file

@ -41,7 +41,6 @@
#include "gui/widgets/window.hpp"
#include "image.hpp"
#include "language.hpp"
#include "savegame.hpp"
#include "serialization/string_utils.hpp"
#include <cctype>
@ -89,30 +88,23 @@ namespace gui2
REGISTER_DIALOG(game_load)
tgame_load::tgame_load(const config& cache_config)
: txtFilter_(register_text("txtFilter", true))
, chk_change_difficulty_(register_bool("change_difficulty", true))
, chk_show_replay_(register_bool("show_replay", true))
, chk_cancel_orders_(register_bool("cancel_orders", true))
, filename_()
, change_difficulty_(false)
, show_replay_(false)
, cancel_orders_(false)
tgame_load::tgame_load(const config& cache_config, savegame::load_game_metadata& data)
: filename_(data.filename)
, change_difficulty_(register_bool("change_difficulty", true, data.select_difficulty))
, show_replay_(register_bool("show_replay", true, data.show_replay))
, cancel_orders_(register_bool("cancel_orders", true, data.cancel_orders))
, summary_(data.summary)
, games_({savegame::get_saves_list()})
, cache_config_(cache_config)
, last_words_()
, summary_()
{
}
void tgame_load::pre_show(twindow& window)
{
assert(txtFilter_);
find_widget<tminimap>(&window, "minimap", false).set_config(&cache_config_);
ttext_box* filter
= find_widget<ttext_box>(&window, "txtFilter", false, true);
ttext_box* filter = find_widget<ttext_box>(&window, "txtFilter", false, true);
filter->set_text_changed_callback(
std::bind(&tgame_load::filter_text_changed, this, _1, _2));
@ -169,20 +161,19 @@ void tgame_load::display_savegame(twindow& window)
savegame::save_info& game = games_[selected_row];
filename_ = game.name();
const config& summary = game.summary();
summary_ = game.summary();
find_widget<tminimap>(&window, "minimap", false)
.set_map_data(summary["map_data"]);
.set_map_data(summary_["map_data"]);
find_widget<tlabel>(&window, "lblScenario", false)
.set_label(summary["label"]);
.set_label(summary_["label"]);
tlistbox& leader_list = find_widget<tlistbox>(&window, "leader_list", false);
leader_list.clear();
for(const auto& leader : summary.child_range("leader")) {
for(const auto& leader : summary_.child_range("leader")) {
std::map<std::string, string_map> data;
string_map item;
@ -209,21 +200,16 @@ void tgame_load::display_savegame(twindow& window)
std::stringstream str;
str << game.format_time_local() << "\n";
evaluate_summary_string(str, summary);
evaluate_summary_string(str, summary_);
find_widget<tlabel>(&window, "lblSummary", false).set_label(str.str());
ttoggle_button& replay_toggle =
find_widget<ttoggle_button>(&window, "show_replay", false);
ttoggle_button& replay_toggle = dynamic_cast<ttoggle_button&>(*show_replay_->widget());
ttoggle_button& cancel_orders_toggle = dynamic_cast<ttoggle_button&>(*cancel_orders_->widget());
ttoggle_button& change_difficulty_toggle = dynamic_cast<ttoggle_button&>(*change_difficulty_->widget());
ttoggle_button& cancel_orders_toggle =
find_widget<ttoggle_button>(&window, "cancel_orders", false);
ttoggle_button& change_difficulty_toggle =
find_widget<ttoggle_button>(&window, "change_difficulty", false);
const bool is_replay = savegame::loadgame::is_replay_save(summary);
const bool is_scenario_start = summary["turn"].empty();
const bool is_replay = savegame::loadgame::is_replay_save(summary_);
const bool is_scenario_start = summary_["turn"].empty();
// Always toggle show_replay on if the save is a replay
replay_toggle.set_value(is_replay);
@ -278,19 +264,14 @@ void tgame_load::filter_text_changed(ttext_* textbox, const std::string& text)
}
list.set_row_shown(show_items);
}
void tgame_load::post_show(twindow& window)
{
change_difficulty_ = chk_change_difficulty_->get_widget_value(window);
show_replay_ = chk_show_replay_->get_widget_value(window);
cancel_orders_ = chk_cancel_orders_->get_widget_value(window);
const bool any_shown = list.any_rows_shown();
if(!games_.empty()) {
const int index =
find_widget<tlistbox>(&window, "savegame_list", false).get_selected_row();
summary_ = games_[index].summary();
}
// Disable Load button if no games are available
find_widget<tbutton>(&window, "ok", false).set_active(any_shown);
// Diable 'Enter' loading if no games are available
window.set_enter_disabled(!any_shown);
}
void tgame_load::evaluate_summary_string(std::stringstream& str,

View file

@ -16,6 +16,8 @@
#define GUI_DIALOGS_LOAD_GAME_HPP_INCLUDED
#include "gui/dialogs/dialog.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "savegame.hpp"
#include "save_index.hpp"
#include "tstring.hpp"
@ -28,37 +30,22 @@ class ttext_;
class tgame_load : public tdialog
{
public:
explicit tgame_load(const config& cache_config);
tgame_load(const config& cache_config, savegame::load_game_metadata& data);
const std::string& filename() const
static bool execute(const config& cache_config, savegame::load_game_metadata& data, CVideo& video)
{
return filename_;
}
bool change_difficulty() const
{
return change_difficulty_;
}
bool show_replay() const
{
return show_replay_;
}
bool cancel_orders() const
{
return cancel_orders_;
}
const config& summary()
{
return summary_;
if(savegame::get_saves_list().empty()) {
gui2::show_transient_message(video, _("No Saved Games"), _("There are no save files to load"));
return false;
}
return tgame_load(cache_config, data).show(video);
}
protected:
private:
/** Inherited from tdialog. */
void pre_show(twindow& window);
/** Inherited from tdialog. */
void post_show(twindow& window);
private:
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
virtual const std::string& window_id() const;
@ -66,25 +53,20 @@ private:
void delete_button_callback(twindow& window);
void display_savegame(twindow& window);
void evaluate_summary_string(std::stringstream& str,
const config& cfg_summary);
void evaluate_summary_string(std::stringstream& str, const config& cfg_summary);
tfield_text* txtFilter_;
tfield_bool* chk_change_difficulty_;
tfield_bool* chk_show_replay_;
tfield_bool* chk_cancel_orders_;
std::string& filename_;
std::string filename_;
bool change_difficulty_;
bool show_replay_;
bool cancel_orders_;
tfield_bool* change_difficulty_;
tfield_bool* show_replay_;
tfield_bool* cancel_orders_;
config& summary_;
std::vector<savegame::save_info> games_;
const config& cache_config_;
std::vector<std::string> last_words_;
config summary_;
};
}

View file

@ -85,46 +85,16 @@ loadgame::loadgame(CVideo& video, const config& game_config, saved_game& gamesta
: game_config_(game_config)
, video_(video)
, gamestate_(gamestate)
, filename_()
, difficulty_()
, load_config_()
, show_replay_(false)
, cancel_orders_(false)
, select_difficulty_(false)
, summary_()
, load_data_()
{}
void loadgame::show_dialog()
bool loadgame::show_difficulty_dialog()
{
if(get_saves_list().empty()) {
gui2::show_transient_message(video_, _("No Saved Games"),
_("There are no save files to load"));
return;
if(load_data_.summary["corrupt"].to_bool()) {
return false;
}
// FIXME: Integrate the load_game dialog into this class
// something to watch for the curious, but not yet ready to go
gui2::tgame_load load_dialog(game_config_);
load_dialog.show(video_);
if (load_dialog.get_retval() == gui2::twindow::OK) {
select_difficulty_ = load_dialog.change_difficulty();
filename_ = load_dialog.filename();
show_replay_ = load_dialog.show_replay();
cancel_orders_ = load_dialog.cancel_orders();
summary_ = load_dialog.summary();
}
}
void loadgame::show_difficulty_dialog()
{
if(summary_["corrupt"].to_bool()) {
return;
}
std::string campaign_id = summary_["campaign"];
std::string campaign_id = load_data_.summary["campaign"];
for(const config &campaign : game_config_.child_range("campaign"))
{
@ -135,36 +105,43 @@ void loadgame::show_difficulty_dialog()
gui2::tcampaign_difficulty difficulty_dlg(campaign);
difficulty_dlg.show(video_);
// Return if canceled, since otherwise difficulty_ will be set to 'CANCEL'
// Return if canceled, since otherwise load_data_.difficulty will be set to 'CANCEL'
if (difficulty_dlg.get_retval() != gui2::twindow::OK) {
return;
return false;
}
difficulty_ = difficulty_dlg.selected_difficulty();
load_data_.difficulty = difficulty_dlg.selected_difficulty();
// Exit loop
break;
}
return true;
}
// Called only by play_controller to handle in-game attempts to load. Instead of returning true,
// throws a "load_game_exception" to signal a resulting load game request.
bool loadgame::load_game()
{
if (!video_.faked()) {
show_dialog();
if(!video_.faked()) {
if(!gui2::tgame_load::execute(game_config_, load_data_, video_)) {
return false;
}
}
if(filename_.empty()) {
if(load_data_.filename.empty()) {
return false;
}
if (select_difficulty_)
show_difficulty_dialog();
if(load_data_.select_difficulty) {
if(!show_difficulty_dialog()) {
return false;
}
}
// Confirm the integrity of the file before throwing the exception.
// Use the summary in the save_index for this.
const config & summary = save_index_manager.get(filename_);
const config & summary = save_index_manager.get(load_data_.filename);
if (summary["corrupt"].to_bool(false)) {
gui2::show_error_message(video_,
@ -176,7 +153,7 @@ bool loadgame::load_game()
return false;
}
throw game::load_game_exception(filename_, show_replay_, cancel_orders_, select_difficulty_, difficulty_, true);
throw game::load_game_exception(load_data_.filename, load_data_.show_replay, load_data_.cancel_orders, load_data_.select_difficulty, load_data_.difficulty, true);
}
bool loadgame::load_game(
@ -187,28 +164,33 @@ bool loadgame::load_game(
, const std::string& difficulty
, bool skip_version_check)
{
filename_ = filename;
difficulty_ = difficulty;
select_difficulty_ = select_difficulty;
load_data_.filename = filename;
load_data_.difficulty = difficulty;
load_data_.select_difficulty = select_difficulty;
if (filename_.empty()){
show_dialog();
}
else{
show_replay_ = show_replay;
cancel_orders_ = cancel_orders;
if(load_data_.filename.empty()){
if(!gui2::tgame_load::execute(game_config_, load_data_, video_)) {
return false;
}
} else {
load_data_.show_replay = show_replay;
load_data_.cancel_orders = cancel_orders;
}
if (filename_.empty())
if(load_data_.filename.empty()) {
return false;
}
if (select_difficulty_)
show_difficulty_dialog();
if(load_data_.select_difficulty) {
if(!show_difficulty_dialog()) {
return false;
}
}
std::string error_log;
read_save_file(filename_, load_config_, &error_log);
read_save_file(load_data_.filename, load_data_.load_config, &error_log);
convert_old_saves(load_config_);
convert_old_saves(load_data_.load_config);
if(!error_log.empty()) {
try {
@ -222,11 +204,11 @@ bool loadgame::load_game(
}
}
if (!difficulty_.empty()){
load_config_["difficulty"] = difficulty_;
if (!load_data_.difficulty.empty()){
load_data_.load_config["difficulty"] = load_data_.difficulty;
}
// read classification to for loading the game_config config object.
gamestate_.classification() = game_classification(load_config_);
gamestate_.classification() = game_classification(load_data_.load_config);
if (skip_version_check) {
return true;
@ -285,14 +267,16 @@ bool loadgame::check_version_compatibility(const version_info & save_version, CV
void loadgame::set_gamestate()
{
gamestate_.set_data(load_config_);
gamestate_.set_data(load_data_.load_config);
}
bool loadgame::load_multiplayer_game()
{
show_dialog();
if(!gui2::tgame_load::execute(game_config_, load_data_, video_)) {
return false;
}
if(filename_.empty()) {
if(load_data_.filename.empty()) {
return false;
}
@ -303,8 +287,8 @@ bool loadgame::load_multiplayer_game()
cursor::setter cur(cursor::WAIT);
log_scope("load_game");
read_save_file(filename_, load_config_, &error_log);
copy_era(load_config_);
read_save_file(load_data_.filename, load_data_.load_config, &error_log);
copy_era(load_data_.load_config);
}
if(!error_log.empty()) {
@ -314,14 +298,14 @@ bool loadgame::load_multiplayer_game()
return false;
}
if(is_replay_save(summary_)) {
if(is_replay_save(load_data_.summary)) {
gui2::show_transient_message(video_, _("Load Game"), _("Replays are not supported in multiplayer mode."));
return false;
}
// We want to verify the game classification before setting the data, so we don't check on
// gamestate_.classification() and instead construct a game_classification object manually.
if(game_classification(load_config_).campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
if(game_classification(load_data_.load_config).campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
gui2::show_transient_error_message(video_, _("This is not a multiplayer save."));
return false;
}

View file

@ -32,6 +32,29 @@ bool save_game_exists(const std::string& name, compression::format compressed);
/** Delete all autosaves of a certain scenario. */
void clean_saves(const std::string& label);
struct load_game_metadata {
/** Name of the savefile to be loaded. */
std::string filename;
/** The difficulty the save is meant to be loaded with. */
std::string difficulty;
/** State of the "show_replay" checkbox in the load-game dialog. */
bool show_replay;
/** State of the "cancel_orders" checkbox in the load-game dialog. */
bool cancel_orders;
/** State of the "change_difficulty" checkbox in the load-game dialog. */
bool select_difficulty;
/** Summary config of the save selected in the load game dialog. */
config summary;
/** Config information of the savefile to be loaded. */
config load_config;
};
/** The class for loading a savefile. */
class loadgame
{
@ -58,9 +81,9 @@ public:
void set_gamestate();
// Getter-methods
bool show_replay() const { return show_replay_; }
bool cancel_orders() const { return cancel_orders_; }
const std::string & filename() const { return filename_; }
bool show_replay() const { return load_data_.show_replay; }
bool cancel_orders() const { return load_data_.cancel_orders; }
const std::string & filename() const { return load_data_.filename; }
/** GUI Dialog sequence which confirms attempts to load saves from previous game versions. */
static bool check_version_compatibility(const version_info & version, CVideo & video);
@ -71,10 +94,8 @@ public:
}
private:
/** Display the load-game dialog. */
void show_dialog();
/** Display the difficulty dialog. */
void show_difficulty_dialog();
bool show_difficulty_dialog();
/** Call check_version_compatibility above, using the version of this savefile. */
bool check_version_compatibility();
/** Copy era information into the snapshot. */
@ -84,13 +105,8 @@ private:
CVideo& video_;
saved_game& gamestate_; /** Primary output information. */
std::string filename_; /** Name of the savefile to be loaded. */
std::string difficulty_; /** The difficulty the save is meant to be loaded with. */
config load_config_; /** Config information of the savefile to be loaded. */
bool show_replay_; /** State of the "show_replay" checkbox in the load-game dialog. */
bool cancel_orders_; /** State of the "cancel_orders" checkbox in the load-game dialog. */
bool select_difficulty_; /** State of the "change_difficulty" checkbox in the load-game dialog. */
config summary_; /** Summary config of the save selected in the load game dialog. */
load_game_metadata load_data_;
};
/**