Load Game: display all human-controlled leaders

This also includes a fix for leader images sometimes not being shown in the dialog.
If the save_index was deleted or altered at a time other than when creating a save,
the image path would be empty in the game load dialog. This ensures the image path
is only saved in binary-path independent form if the path isn't empty. In that case,
the plain image path from the savefile is saved. Either way, the image path is checked
in-dialog, first plain, then as binary-path independent. If both fail, a fallback image
is shown.
This commit is contained in:
Charles Dang 2016-08-25 22:33:33 +11:00
parent 5497b09321
commit ca58a6b7c3
3 changed files with 157 additions and 78 deletions

View file

@ -26,6 +26,11 @@
fixed_width = "true"
[/linked_group]
[linked_group]
id = "leader_image"
fixed_width = "true"
[/linked_group]
[tooltip]
id = "tooltip"
[/tooltip]
@ -84,9 +89,10 @@
border = "all"
border_size = 5
horizontal_alignment = "right"
vertical_grow = "true"
horizontal_grow = "true"
{GUI_FORCE_WIDGET_MINIMUM_SIZE 200 200 (
{GUI_FORCE_WIDGET_MINIMUM_SIZE 250 200 (
[minimap]
id = "minimap"
definition = "no_size"
@ -137,24 +143,83 @@
[/row]
{GUI_HORIZONTAL_SPACER_LINE}
[row]
grow_factor = 1
[column]
grow_factor = 1
border = "all"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[image]
id = "imgLeader"
definition = "default"
[/image]
border = "all"
border_size = 5
[listbox]
id = "leader_list"
has_minimum = "false"
[list_definition]
[row]
[column]
grow_factor = 1
horizontal_grow = "true"
[toggle_panel]
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[image]
id = "imgLeader"
definition = "default"
linked_group = "leader_image"
[/image]
[/column]
[column]
grow_factor = 1
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "leader_name"
definition = "default"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[/grid]
@ -330,7 +395,7 @@
horizontal_grow = "true"
[grid]
[row]
[column]
@ -348,7 +413,7 @@
[/toggle_button]
[/column]
[column]
grow_factor = 0
horizontal_alignment = "right"

View file

@ -16,6 +16,7 @@
#include "gui/dialogs/game_load.hpp"
#include "filesystem.hpp"
#include "formula/string_utils.hpp"
#include "gettext.hpp"
#include "game_config.hpp"
@ -38,6 +39,7 @@
#include "gui/widgets/text_box.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/window.hpp"
#include "image.hpp"
#include "language.hpp"
#include "savegame.hpp"
#include "serialization/string_utils.hpp"
@ -170,15 +172,41 @@ void tgame_load::display_savegame(twindow& window)
const config& summary = game.summary();
find_widget<timage>(&window, "imgLeader", false)
.set_label(summary["leader_image"]);
find_widget<tminimap>(&window, "minimap", false)
.set_map_data(summary["map_data"]);
find_widget<tlabel>(&window, "lblScenario", false)
.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")) {
std::map<std::string, string_map> data;
string_map item;
// First, we evaluate whether the leader image as provided exists.
// If not, we try getting a binary-path independent path. If that still doesn't
// work, we fallback on unknown-unit.png.
std::string leader_image = leader["leader_image"].str();
if(!image::exists(leader_image)) {
leader_image = filesystem::get_independent_image_path(leader_image);
}
if(leader_image.empty()) {
leader_image = "units/unknown-unit.png";
}
item["label"] = leader_image;
data.emplace("imgLeader", item);
item["label"] = leader["leader_name"];
data.emplace("leader_name", item);
leader_list.add_row(data);
}
std::stringstream str;
str << game.format_time_local() << "\n";
evaluate_summary_string(str, summary);

View file

@ -333,13 +333,13 @@ save_info create_save_info::operator()(const std::string& filename) const
void extract_summary_from_config(config& cfg_save, config& cfg_summary)
{
const config &cfg_snapshot = cfg_save.child("snapshot");
const config& cfg_snapshot = cfg_save.child("snapshot");
//Servergenerated replays contain [scenario] and no [replay_start]
const config &cfg_replay_start = cfg_save.child("replay_start") ? cfg_save.child("replay_start") : cfg_save.child("scenario") ;
const config& cfg_replay_start = cfg_save.child("replay_start") ? cfg_save.child("replay_start") : cfg_save.child("scenario") ;
const config &cfg_replay = cfg_save.child("replay");
const config& cfg_replay = cfg_save.child("replay");
const bool has_replay = cfg_replay && !cfg_replay.empty();
const bool has_snapshot = cfg_snapshot && cfg_snapshot.child("side");
const bool has_snapshot = cfg_snapshot && cfg_snapshot.has_child("side");
cfg_summary["replay"] = has_replay;
cfg_summary["snapshot"] = has_snapshot;
@ -356,84 +356,70 @@ void extract_summary_from_config(config& cfg_save, config& cfg_summary)
cfg_summary["difficulty"] = cfg_save["difficulty"];
cfg_summary["random_mode"] = cfg_save["random_mode"];
cfg_summary["campaign"] = cfg_save["campaign"];
cfg_summary["version"] = cfg_save["version"];
cfg_summary["corrupt"] = "";
if(has_snapshot) {
cfg_summary["turn"] = cfg_snapshot["turn_at"];
if (cfg_snapshot["turns"] != "-1") {
if(cfg_snapshot["turns"] != "-1") {
cfg_summary["turn"] = cfg_summary["turn"].str() + "/" + cfg_snapshot["turns"].str();
}
}
// Find the first human leader so we can display their icon in the load menu.
/** @todo Ideally we should grab all leaders if there's more than 1 human player? */
std::string leader;
std::string leader_image;
std::string leader_image_tc_modifier;
//for (const config &p : cfg_save.child_range("player"))
//{
// if (p["canrecruit"].to_bool(false))) {
// leader = p["save_id"];
// }
//}
// Find the human leaders so we can display their icons and names in the load menu.
config leader_config;
bool shrouded = false;
//if (!leader.empty())
//{
if (const config &snapshot = *(has_snapshot ? &cfg_snapshot : &cfg_replay_start))
{
for (const config &side : snapshot.child_range("side"))
{
if (side["controller"] != team::CONTROLLER::enum_to_string(team::CONTROLLER::HUMAN)) {
if(const config& snapshot = *(has_snapshot ? &cfg_snapshot : &cfg_replay_start)) {
for(const config &side : snapshot.child_range("side")) {
std::string leader;
std::string leader_image;
std::string leader_image_tc_modifier;
std::string leader_name;
if(side["controller"] != team::CONTROLLER::enum_to_string(team::CONTROLLER::HUMAN)) {
continue;
}
if(side["shroud"].to_bool()) {
shrouded = true;
}
for(const config &u : side.child_range("unit")) {
if(!u["canrecruit"].to_bool()) {
continue;
}
if (side["shroud"].to_bool()) {
shrouded = true;
}
leader = u["id"].str();
leader_name = u["name"].str();
leader_image = u["image"].str();
leader_image_tc_modifier = "~RC(" + u["flag_rgb"].str() + ">" + u["side"].str() + ")";
if (side["canrecruit"].to_bool())
{
leader = side["id"].str();
leader_image = side["image"].str();
leader_image_tc_modifier = "~RC(magenta>" + side["color"].str() + ")"; // Hardcode magenta
break;
}
for (const config &u : side.child_range("unit"))
{
if (u["canrecruit"].to_bool()) {
leader = u["id"].str();
leader_image = u["image"].str();
if(!u["flag_rgb"].empty()) {
leader_image_tc_modifier = "~RC(" + u["flag_rgb"].str() + ">" + u["side"].str() + ")";
}
break;
}
}
// Exit on first human leader
break;
}
// We need a binary path-independent path to the leader image here so it can be displayed
// for campaign-specific units even when the campaign isn't loaded yet.
std::string leader_image_path = filesystem::get_independent_image_path(leader_image);
// If the image path was found, we append the leader TC modifier. If it's not (such as in
// the case where the binary path hasn't been loaded yet, perhaps due to save_index being
// deleted), the unaltered image path is used and will be parsed by get_independent_image_path
// at runtime.
if(!leader_image_path.empty()) {
leader_image_path += leader_image_tc_modifier;
leader_image = leader_image_path;
}
leader_config["leader"] = leader;
leader_config["leader_name"] = leader_name;
leader_config["leader_image"] = leader_image;
cfg_summary.add_child("leader", leader_config);
}
//}
cfg_summary["leader"] = leader;
// We need a binary path-independent path to the leader image here
// so it can be displayed for campaign-specific units in the dialog
// even when the campaign isn't loaded yet.
cfg_summary["leader_image"] = filesystem::get_independent_image_path(leader_image);
// Append the leader image's team coloring
if(!cfg_summary["leader_image"].empty()) {
cfg_summary["leader_image"] = cfg_summary["leader_image"].str() + leader_image_tc_modifier;
}
if(!shrouded) {