added new 'load' dialog.
changed behavior of pressing 'space' to end a unit's turn
This commit is contained in:
parent
7c941fa370
commit
f0df140327
26 changed files with 499 additions and 48 deletions
|
@ -67,6 +67,7 @@ Defeat:
|
|||
side=1
|
||||
canrecruit=1
|
||||
controller=human
|
||||
gold=200
|
||||
[/side]
|
||||
|
||||
[side]
|
||||
|
|
|
@ -175,12 +175,16 @@ hordes_undead="The Dark Hordes"
|
|||
|
||||
error_no_campaigns="There are no campaigns available"
|
||||
|
||||
new_campaign="Campaign"
|
||||
choose_campaign="Choose the campaign you want to play:"
|
||||
|
||||
difficulty="Difficulty"
|
||||
difficulty_level="Select difficulty level:"
|
||||
EASY="&elvish-fighter.png,Fighter (easy)"
|
||||
NORMAL="*&elvish-hero.png,Hero (medium)"
|
||||
HARD="&elvish-champion.png,Champion (hard)"
|
||||
EASY="Easy"
|
||||
NORMAL="Medium"
|
||||
HARD="Hard"
|
||||
|
||||
save_invalid="#(Invalid)"
|
||||
|
||||
lawful_description="Lawful units fight better at day, and worse at night.
|
||||
|
||||
|
@ -329,6 +333,7 @@ multiplayer_button="Multiplayer"
|
|||
quit_button="Quit"
|
||||
quit="Quit Game"
|
||||
language_button="Language"
|
||||
scenario_start="Scenario Start"
|
||||
|
||||
help_string_tutorial_button="Start a tutorial to familiarize yourself with the game"
|
||||
help_string_campaign_button="Start a new single player campaign"
|
||||
|
@ -823,4 +828,8 @@ ally="Allied"
|
|||
owned="Owned"
|
||||
neutral="Neutral"
|
||||
|
||||
import_saves_caption="Import Saved Games"
|
||||
import_old_saves="Your saves directory contains some files from an old version of Battle for Wesnoth. Would you like to update these to the latest version? This may take some time."
|
||||
import_saves="Your saves directory contains some files that don't appear to have been generated by this version of Battle for Wesnoth. Would you like to register these files with the game?"
|
||||
|
||||
[/language]
|
||||
|
|
|
@ -641,6 +641,7 @@ void attack(display& gui, const gamemap& map,
|
|||
attackerxp = game_config::kill_experience/2;
|
||||
|
||||
a->second.get_experience(attackerxp);
|
||||
gui.invalidate(a->first);
|
||||
attackerxp = 0;
|
||||
defenderxp = 0;
|
||||
|
||||
|
@ -779,6 +780,7 @@ void attack(display& gui, const gamemap& map,
|
|||
defenderxp = game_config::kill_experience/2;
|
||||
|
||||
d->second.get_experience(defenderxp);
|
||||
gui.invalidate(d->first);
|
||||
defenderxp = 0;
|
||||
attackerxp = 0;
|
||||
|
||||
|
@ -854,10 +856,12 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
if(attackerxp) {
|
||||
a->second.get_experience(attackerxp);
|
||||
gui.invalidate(a->first);
|
||||
}
|
||||
|
||||
if(defenderxp) {
|
||||
d->second.get_experience(defenderxp);
|
||||
gui.invalidate(d->first);
|
||||
}
|
||||
|
||||
gui.invalidate_unit();
|
||||
|
|
|
@ -1114,7 +1114,7 @@ void config::clear_children(const std::string& key)
|
|||
children.erase(key);
|
||||
}
|
||||
|
||||
config* config::remove_child(const std::string& key, size_t index)
|
||||
void config::remove_child(const std::string& key, size_t index)
|
||||
{
|
||||
//remove from the ordering
|
||||
const child_pos pos(children.find(key),index);
|
||||
|
@ -1133,7 +1133,7 @@ config* config::remove_child(const std::string& key, size_t index)
|
|||
assert(index < v.size());
|
||||
config* const res = v[index];
|
||||
v.erase(v.begin()+index);
|
||||
return res;
|
||||
delete res;
|
||||
}
|
||||
|
||||
std::string& config::operator[](const std::string& key)
|
||||
|
|
|
@ -151,7 +151,7 @@ struct config
|
|||
const std::string& value) const;
|
||||
|
||||
void clear_children(const std::string& key);
|
||||
config* remove_child(const std::string& key, size_t index);
|
||||
void remove_child(const std::string& key, size_t index);
|
||||
|
||||
// REMOVE_EMPTY : remove empty elements
|
||||
// STRIP_SPACES : strips leading and trailing blank spaces
|
||||
|
|
182
src/dialogs.cpp
182
src/dialogs.cpp
|
@ -15,11 +15,13 @@
|
|||
#include "events.hpp"
|
||||
#include "font.hpp"
|
||||
#include "language.hpp"
|
||||
#include "log.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "util.hpp"
|
||||
#include "widgets/file_chooser.hpp"
|
||||
#include "widgets/progressbar.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
|
@ -199,7 +201,7 @@ gui::dialog_button_action::RESULT delete_save::button_pressed(int menu_selection
|
|||
|
||||
} //end anon namespace
|
||||
|
||||
std::string load_game_dialog(display& disp, bool* show_replay)
|
||||
std::string load_game_dialog(display& disp, const config& game_config, const game_data& data, bool* show_replay)
|
||||
{
|
||||
std::vector<save_info> games = get_saves_list();
|
||||
|
||||
|
@ -216,8 +218,93 @@ std::string load_game_dialog(display& disp, bool* show_replay)
|
|||
return "";
|
||||
}
|
||||
|
||||
std::vector<size_t> no_summary; //all items that aren't in the summary table
|
||||
std::vector<config*> summaries;
|
||||
std::vector<save_info>::const_iterator i;
|
||||
for(i = games.begin(); i != games.end(); ++i) {
|
||||
config& cfg = save_summary(i->name);
|
||||
if(cfg["campaign_type"].empty() && cfg["corrupt"] != "yes" || lexical_cast<int>(cfg["mod_time"]) != static_cast<int>(i->time_modified)) {
|
||||
no_summary.push_back(i - games.begin());
|
||||
}
|
||||
|
||||
summaries.push_back(&cfg);
|
||||
}
|
||||
|
||||
bool generate_summaries = !no_summary.empty();
|
||||
|
||||
//if there are more than 5 saves without a summary, it may take a substantial
|
||||
//amount of time to convert them over. Ask the user if they want to do this
|
||||
if(no_summary.size() > 5) {
|
||||
|
||||
if(preferences::cache_saves() == preferences::CACHE_SAVES_NEVER) {
|
||||
generate_summaries = false;
|
||||
} else if(preferences::cache_saves() == preferences::CACHE_SAVES_ALWAYS) {
|
||||
generate_summaries = true;
|
||||
} else {
|
||||
std::string caption = "import_saves_caption", message = "import_old_saves";
|
||||
|
||||
//if there are already some cached games, then we assume that the user is importing new
|
||||
//games, and it's not a total import, so tailor the message accordingly
|
||||
if(no_summary.size() < games.size()) {
|
||||
message = "import_saves";
|
||||
}
|
||||
|
||||
std::vector<gui::check_item> options;
|
||||
options.push_back(gui::check_item(string_table["dont_ask_again"],false));
|
||||
const int res = gui::show_dialog(disp,NULL,string_table[caption],string_table[message],
|
||||
gui::YES_NO,NULL,NULL,"",NULL,NULL,&options);
|
||||
|
||||
generate_summaries = res == 0;
|
||||
if(options.front().checked) {
|
||||
preferences::set_cache_saves(generate_summaries ? preferences::CACHE_SAVES_ALWAYS : preferences::CACHE_SAVES_NEVER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(generate_summaries) {
|
||||
const events::event_context context;
|
||||
gui::progress_bar bar(disp);
|
||||
const SDL_Rect bar_area = {disp.x()/2 - 100, disp.y()/2 - 20, 200, 40};
|
||||
bar.set_location(bar_area);
|
||||
|
||||
for(std::vector<size_t>::const_iterator s = no_summary.begin(); s != no_summary.end(); ++s) {
|
||||
bar.set_progress_percent(((s - no_summary.begin())*100)/no_summary.size());
|
||||
events::raise_draw_event();
|
||||
events::pump();
|
||||
disp.update_display();
|
||||
|
||||
log_scope("load");
|
||||
std::cerr << "loading game: '" << games[*s].name << "'\n";
|
||||
game_state state;
|
||||
|
||||
config& summary = save_summary(games[*s].name);
|
||||
|
||||
try {
|
||||
summary["mod_time"] = str_cast(lexical_cast<int>(games[*s].time_modified));
|
||||
load_game(data,games[*s].name,state);
|
||||
extract_summary_data_from_save(state,summary);
|
||||
} catch(io_exception&) {
|
||||
summary["corrupt"] = "yes";
|
||||
std::cerr << "save '" << games[*s].name << "' could not be loaded (io_exception)\n";
|
||||
} catch(config::error&) {
|
||||
summary["corrupt"] = "yes";
|
||||
std::cerr << "save '" << games[*s].name << "' could not be loaded (config parse error)\n";
|
||||
} catch(gamestatus::load_game_failed&) {
|
||||
summary["corrupt"] = "yes";
|
||||
std::cerr << "save '" << games[*s].name << "' could not be loaded (load_game_failed exception)\n";
|
||||
}
|
||||
|
||||
std::cerr << "loaded...\n";
|
||||
}
|
||||
|
||||
write_save_index();
|
||||
}
|
||||
|
||||
util::scoped_ptr<gamemap> map_ptr(NULL);
|
||||
string_map map_cache;
|
||||
|
||||
std::vector<std::string> items;
|
||||
for(std::vector<save_info>::const_iterator i = games.begin(); i != games.end(); ++i) {
|
||||
for(i = games.begin(); i != games.end(); ++i) {
|
||||
std::string name = i->name;
|
||||
name.resize(minimum<size_t>(name.size(),40));
|
||||
|
||||
|
@ -227,8 +314,89 @@ std::string load_game_dialog(display& disp, bool* show_replay)
|
|||
time_buf[0] = 0;
|
||||
|
||||
std::stringstream str;
|
||||
|
||||
config& summary = *summaries[i - games.begin()];
|
||||
const game_data::unit_type_map::const_iterator leader = data.unit_types.find(summary["leader"]);
|
||||
if(leader != data.unit_types.end()) {
|
||||
str << "&" << leader->second.image() << ",";
|
||||
} else {
|
||||
str << ",";
|
||||
}
|
||||
|
||||
// escape all special characters in filenames
|
||||
str << config::escape(name) << "," << time_buf;
|
||||
str << font::BOLD_TEXT << config::escape(name) << "\n" << time_buf;
|
||||
|
||||
if(summary["corrupt"] == "yes") {
|
||||
str << "\n" << string_table["save_invalid"];
|
||||
} else if(summary["campaign_type"] != "") {
|
||||
str << "\n";
|
||||
|
||||
const std::string& campaign_type = summary["campaign_type"];
|
||||
if(campaign_type == "scenario") {
|
||||
str << translate_string("campaign_button");
|
||||
} else if(campaign_type == "multiplayer") {
|
||||
str << translate_string("multiplayer_button");
|
||||
} else if(campaign_type == "tutorial") {
|
||||
str << translate_string("tutorial_button");
|
||||
} else {
|
||||
str << translate_string(campaign_type);
|
||||
}
|
||||
|
||||
str << "\n";
|
||||
|
||||
if(summary["snapshot"] == "no" && summary["replay"] == "yes") {
|
||||
str << translate_string("replay");
|
||||
} else if(summary["turn"] != "") {
|
||||
str << translate_string("turn") << " " << summary["turn"];
|
||||
} else {
|
||||
str << string_table["scenario_start"];
|
||||
}
|
||||
|
||||
str << "\n" << translate_string("difficulty") << ": " << translate_string(summary["difficulty"]);
|
||||
|
||||
std::string map_data = summary["map_data"];
|
||||
if(map_data.empty()) {
|
||||
const config* const scenario = game_config.find_child(summary["campaign_type"],"id",summary["scenario"]);
|
||||
if(scenario != NULL) {
|
||||
map_data = (*scenario)["map_data"];
|
||||
if(map_data.empty() && (*scenario)["map"].empty() == false) {
|
||||
try {
|
||||
map_data = read_map((*scenario)["map"]);
|
||||
} catch(io_exception& e) {
|
||||
std::cerr << "could not read map '" << (*scenario)["map"] << "': " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(map_data.empty() == false) {
|
||||
const string_map::const_iterator itor = map_cache.find(map_data);
|
||||
if(itor != map_cache.end()) {
|
||||
str << ",&" << itor->second;
|
||||
} else {
|
||||
|
||||
try {
|
||||
if(map_ptr == NULL) {
|
||||
map_ptr.assign(new gamemap(game_config,map_data));
|
||||
} else {
|
||||
map_ptr->read(map_data);
|
||||
}
|
||||
|
||||
SDL_Surface* const minimap = image::getMinimap(72,72,*map_ptr,0,NULL);
|
||||
if(minimap != NULL) {
|
||||
const std::string id = "_map_image_" + name;
|
||||
image::register_image(id,minimap);
|
||||
str << ",&" << id;
|
||||
|
||||
map_cache[map_data] = id;
|
||||
}
|
||||
} catch(gamemap::incorrect_format_exception& e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
items.push_back(str.str());
|
||||
}
|
||||
|
||||
|
@ -246,9 +414,15 @@ std::string load_game_dialog(display& disp, bool* show_replay)
|
|||
if(res == -1)
|
||||
return "";
|
||||
|
||||
if(show_replay != NULL)
|
||||
if(show_replay != NULL) {
|
||||
*show_replay = options.front().checked;
|
||||
|
||||
const config& summary = *summaries[res];
|
||||
if(summary["replay"] == "yes" && summary["snapshot"] == "no") {
|
||||
*show_replay = true;
|
||||
}
|
||||
}
|
||||
|
||||
return games[res].name;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ int get_save_name(display & disp, const std::string& caption,
|
|||
//of the save they want to load. Stores whether the user wants to show
|
||||
//a replay of the game in show_replay. If show_replay is NULL, then
|
||||
//the user will not be asked if they want to show a replay.
|
||||
std::string load_game_dialog(display& disp, bool* show_replay);
|
||||
std::string load_game_dialog(display& disp, const config& terrain_config, const game_data& data, bool* show_replay);
|
||||
|
||||
void unit_speak(const config& message_info, display& disp, const unit_map& units);
|
||||
|
||||
|
|
|
@ -1109,9 +1109,9 @@ void display::draw_unit_on_tile(int x, int y, SDL_Surface* unit_image_override,
|
|||
energy_file = &game_config::ally_energy_image;
|
||||
}
|
||||
} else {
|
||||
if(activeTeam_ == currentTeam_ && unit_move == unit_total_move) {
|
||||
if(activeTeam_ == currentTeam_ && unit_move == unit_total_move && !it->second.user_end_turn()) {
|
||||
energy_file = &game_config::unmoved_energy_image;
|
||||
} else if(activeTeam_ == currentTeam_ && unit_can_move(loc,units_,map_,teams_)) {
|
||||
} else if(activeTeam_ == currentTeam_ && unit_can_move(loc,units_,map_,teams_) && !it->second.user_end_turn()) {
|
||||
energy_file = &game_config::partmoved_energy_image;
|
||||
} else {
|
||||
energy_file = &game_config::moved_energy_image;
|
||||
|
|
|
@ -149,6 +149,11 @@ std::string get_prefs_file()
|
|||
return get_user_data_dir() + "/preferences";
|
||||
}
|
||||
|
||||
std::string get_save_index_file()
|
||||
{
|
||||
return get_user_data_dir() + "/save_index";
|
||||
}
|
||||
|
||||
std::string get_saves_dir()
|
||||
{
|
||||
const std::string dir_path = get_user_data_dir() + "/saves";
|
||||
|
|
|
@ -34,6 +34,7 @@ void get_files_in_dir(const std::string& dir,
|
|||
std::string get_dir(const std::string &dir);
|
||||
//the location of various important files
|
||||
std::string get_prefs_file();
|
||||
std::string get_save_index_file();
|
||||
std::string get_saves_dir();
|
||||
std::string get_cache_dir();
|
||||
std::string get_user_data_dir();
|
||||
|
|
17
src/font.cpp
17
src/font.cpp
|
@ -162,7 +162,7 @@ const SDL_Color NORMAL_COLOUR = {0xDD,0xDD,0xDD,0},
|
|||
BUTTON_COLOUR = {0xBC,0xB0,0x88,0};
|
||||
|
||||
const char LARGE_TEXT='*', SMALL_TEXT='`', GOOD_TEXT='@', BAD_TEXT='#',
|
||||
NORMAL_TEXT='{', BLACK_TEXT='}', IMAGE='&', NULL_MARKUP='^';
|
||||
NORMAL_TEXT='{', BLACK_TEXT='}', BOLD_TEXT='~', IMAGE='&', NULL_MARKUP='^';
|
||||
|
||||
|
||||
const SDL_Color& get_side_colour(int side)
|
||||
|
@ -259,7 +259,7 @@ SDL_Surface* render_text(TTF_Font* font,const std::string& text, const SDL_Color
|
|||
|
||||
//function which will parse the markup tags at the front of a string
|
||||
std::string::const_iterator parse_markup(std::string::const_iterator i1, std::string::const_iterator i2,
|
||||
int* font_size, SDL_Color* colour)
|
||||
int* font_size, SDL_Color* colour, int* style)
|
||||
{
|
||||
if(font_size == NULL || colour == NULL) {
|
||||
return i1;
|
||||
|
@ -289,6 +289,9 @@ std::string::const_iterator parse_markup(std::string::const_iterator i1, std::st
|
|||
case SMALL_TEXT:
|
||||
*font_size -= 2;
|
||||
break;
|
||||
case BOLD_TEXT:
|
||||
*style |= TTF_STYLE_BOLD;
|
||||
break;
|
||||
case NULL_MARKUP:
|
||||
return i1+1;
|
||||
default:
|
||||
|
@ -430,15 +433,16 @@ SDL_Rect draw_text(display* gui, const SDL_Rect& area, int size,
|
|||
for(;;) {
|
||||
SDL_Color col = colour;
|
||||
int sz = size;
|
||||
int text_style = style;
|
||||
|
||||
i1 = parse_markup(i1,i2,&sz,&col);
|
||||
i1 = parse_markup(i1,i2,&sz,&col,&text_style);
|
||||
|
||||
if(i1 != i2) {
|
||||
std::string new_string(i1,i2);
|
||||
|
||||
config::unescape(new_string);
|
||||
|
||||
const SDL_Rect rect = draw_text_line(gui,area,sz,col,new_string,x,y,bg,use_tooltips,style);
|
||||
const SDL_Rect rect = draw_text_line(gui,area,sz,col,new_string,x,y,bg,use_tooltips,text_style);
|
||||
if(rect.w > res.w) {
|
||||
res.w = rect.w;
|
||||
}
|
||||
|
@ -691,13 +695,14 @@ SDL_Surface* floating_label::create_surface()
|
|||
for(std::vector<std::string>::const_iterator ln = lines.begin(); ln != lines.end(); ++ln) {
|
||||
SDL_Color colour = colour_;
|
||||
int size = font_size_;
|
||||
const std::string::const_iterator i1 = font::parse_markup(ln->begin(),ln->end(),&size,&colour);
|
||||
int style = 0;
|
||||
const std::string::const_iterator i1 = font::parse_markup(ln->begin(),ln->end(),&size,&colour,&style);
|
||||
const std::string str(i1,ln->end());
|
||||
|
||||
TTF_Font* const font = get_font(size);
|
||||
|
||||
if(str != "" && font != NULL) {
|
||||
surfaces.push_back(shared_sdl_surface(font::render_text(font,str,colour,0)));
|
||||
surfaces.push_back(shared_sdl_surface(font::render_text(font,str,colour,style)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ extern const SDL_Color NORMAL_COLOUR, GOOD_COLOUR, BAD_COLOUR, BLACK_COLOUR,
|
|||
enum MARKUP { USE_MARKUP, NO_MARKUP };
|
||||
|
||||
//standard markups
|
||||
extern const char LARGE_TEXT, SMALL_TEXT, GOOD_TEXT, BAD_TEXT, NORMAL_TEXT, BLACK_TEXT, IMAGE, NULL_MARKUP;
|
||||
extern const char LARGE_TEXT, SMALL_TEXT, GOOD_TEXT, BAD_TEXT, NORMAL_TEXT, BLACK_TEXT, BOLD_TEXT, IMAGE, NULL_MARKUP;
|
||||
|
||||
//function to draw text on the screen. The text will be clipped to area.
|
||||
//If the text runs outside of area horizontally, an ellipsis will be displayed
|
||||
|
|
|
@ -709,7 +709,7 @@ int play_game(int argc, char** argv)
|
|||
|
||||
bool show_replay = loaded_game_show_replay;
|
||||
|
||||
const std::string game = loaded_game.empty() ? dialogs::load_game_dialog(disp,&show_replay) : loaded_game;
|
||||
const std::string game = loaded_game.empty() ? dialogs::load_game_dialog(disp,game_config,units_data,&show_replay) : loaded_game;
|
||||
|
||||
loaded_game = "";
|
||||
|
||||
|
@ -844,7 +844,7 @@ int play_game(int argc, char** argv)
|
|||
int res = 0;
|
||||
|
||||
if(campaign_names.size() > 1) {
|
||||
res = gui::show_dialog(disp,NULL,"",
|
||||
res = gui::show_dialog(disp,NULL,string_table["new_campaign"],
|
||||
string_table["choose_campaign"],
|
||||
gui::OK_CANCEL,&campaign_names);
|
||||
|
||||
|
@ -867,7 +867,7 @@ int play_game(int argc, char** argv)
|
|||
std::transform(difficulties.begin(),difficulties.end(),difficulty_options.begin(),translate_string);
|
||||
}
|
||||
|
||||
const int res = gui::show_dialog(disp,NULL,"",
|
||||
const int res = gui::show_dialog(disp,NULL,string_table["difficulty"],
|
||||
string_table["difficulty_level"],
|
||||
gui::OK_CANCEL,&difficulty_options);
|
||||
if(res == -1)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "language.hpp"
|
||||
#include "log.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
@ -191,7 +192,7 @@ bool gamestatus::next_turn()
|
|||
return numTurns_ == -1 || turn_ <= size_t(numTurns_);
|
||||
}
|
||||
|
||||
game_state read_game(game_data& data, const config* cfg)
|
||||
game_state read_game(const game_data& data, const config* cfg)
|
||||
{
|
||||
log_scope("read_game");
|
||||
game_state res;
|
||||
|
@ -347,7 +348,7 @@ void delete_game(const std::string& name)
|
|||
remove((get_saves_dir() + "/" + modified_name).c_str());
|
||||
}
|
||||
|
||||
void load_game(game_data& data, const std::string& name, game_state& state)
|
||||
void load_game(const game_data& data, const std::string& name, game_state& state)
|
||||
{
|
||||
log_scope("load_game");
|
||||
std::string modified_name = name;
|
||||
|
@ -373,8 +374,129 @@ void save_game(const game_state& state)
|
|||
config cfg;
|
||||
try {
|
||||
write_game(state,cfg);
|
||||
write_file(get_saves_dir() + "/" + name,cfg.write());
|
||||
|
||||
const std::string fname = get_saves_dir() + "/" + name;
|
||||
write_file(fname,cfg.write());
|
||||
|
||||
config& summary = save_summary(state.label);
|
||||
extract_summary_data_from_save(state,summary);
|
||||
const int mod_time = static_cast<int>(file_create_time(fname));
|
||||
summary["mod_time"] = str_cast(mod_time);
|
||||
|
||||
write_save_index();
|
||||
} catch(io_exception& e) {
|
||||
throw gamestatus::save_game_failed(e.what());
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool save_index_loaded = false;
|
||||
config save_index_cfg;
|
||||
}
|
||||
|
||||
config& save_index()
|
||||
{
|
||||
if(save_index_loaded == false) {
|
||||
try {
|
||||
save_index_cfg.read(read_file(get_save_index_file()));
|
||||
} catch(io_exception& e) {
|
||||
std::cerr << "error reading save index: '" << e.what() << "'\n";
|
||||
} catch(config::error& e) {
|
||||
std::cerr << "error parsing save index config file\n";
|
||||
save_index_cfg.clear();
|
||||
}
|
||||
|
||||
save_index_loaded = true;
|
||||
}
|
||||
|
||||
return save_index_cfg;
|
||||
}
|
||||
|
||||
config& save_summary(const std::string& save)
|
||||
{
|
||||
config& cfg = save_index();
|
||||
config* res = cfg.find_child("save","save",save);
|
||||
if(res == NULL) {
|
||||
res = &cfg.add_child("save");
|
||||
(*res)["save"] = save;
|
||||
}
|
||||
|
||||
return *res;
|
||||
}
|
||||
|
||||
void delete_save_summary(const std::string& save)
|
||||
{
|
||||
config& cfg = save_index();
|
||||
const config* const res = cfg.find_child("save","save",save);
|
||||
if(res != NULL) {
|
||||
const config::child_list& children = cfg.get_children("save");
|
||||
const size_t index = std::find(children.begin(),children.end(),res) - children.begin();
|
||||
cfg.remove_child("save",index);
|
||||
}
|
||||
}
|
||||
|
||||
void write_save_index()
|
||||
{
|
||||
try {
|
||||
write_file(get_save_index_file(),save_index().write());
|
||||
} catch(io_exception& e) {
|
||||
std::cerr << "error writing to save index file: '" << e.what() << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
void extract_summary_data_from_save(const game_state& state, config& out)
|
||||
{
|
||||
const bool has_replay = state.replay_data.empty() == false;
|
||||
const bool has_snapshot = state.snapshot.child("side") != NULL;
|
||||
|
||||
out["replay"] = has_replay ? "yes" : "no";
|
||||
out["snapshot"] = has_snapshot ? "yes" : "no";
|
||||
|
||||
if(has_snapshot) {
|
||||
out["map_data"] = state.snapshot["map_data"];
|
||||
} else if(has_replay) {
|
||||
out["map_data"] = state.starting_pos["map_data"];
|
||||
}
|
||||
|
||||
out["campaign_type"] = state.campaign_type;
|
||||
out["scenario"] = state.scenario;
|
||||
out["difficulty"] = state.difficulty;
|
||||
out["corrupt"] = "";
|
||||
|
||||
if(has_snapshot) {
|
||||
out["turn"] = state.snapshot["turn_at"];
|
||||
if(state.snapshot["turns"] != "-1") {
|
||||
out["turn"] += "/" + state.snapshot["turns"];
|
||||
}
|
||||
}
|
||||
|
||||
//find the first human leader so we can display their icon in the load menu
|
||||
std::string leader;
|
||||
|
||||
for(std::vector<unit>::const_iterator u = state.available_units.begin(); u != state.available_units.end(); ++u) {
|
||||
if(u->can_recruit()) {
|
||||
leader = u->type().name();
|
||||
}
|
||||
}
|
||||
|
||||
if(leader == "") {
|
||||
const config& snapshot = has_snapshot ? state.snapshot : state.starting_pos;
|
||||
const config::child_list& sides = snapshot.get_children("side");
|
||||
for(config::child_list::const_iterator s = sides.begin(); s != sides.end() && leader.empty(); ++s) {
|
||||
|
||||
if((**s)["controller"] != "human") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const config::child_list& units = (**s).get_children("unit");
|
||||
for(config::child_list::const_iterator u = units.begin(); u != units.end(); ++u) {
|
||||
if((**u)["canrecruit"] == "1") {
|
||||
leader = (**u)["type"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out["leader"] = leader;
|
||||
}
|
|
@ -159,18 +159,26 @@ std::vector<save_info> get_saves_list();
|
|||
|
||||
enum WRITE_GAME_MODE { WRITE_SNAPSHOT_ONLY, WRITE_FULL_GAME };
|
||||
|
||||
game_state read_game(game_data& data, const config* cfg);
|
||||
game_state read_game(const game_data& data, const config* cfg);
|
||||
void write_game(const game_state& game, config& cfg, WRITE_GAME_MODE mode=WRITE_FULL_GAME);
|
||||
|
||||
// function returns true iff there is already savegame with that name
|
||||
bool save_game_exists(const std::string & name);
|
||||
|
||||
//functions to load/save games.
|
||||
void load_game(game_data& data, const std::string& name, game_state& state);
|
||||
void load_game(const game_data& data, const std::string& name, game_state& state);
|
||||
//throws gamestatus::save_game_failed
|
||||
void save_game(const game_state& state);
|
||||
|
||||
//function to delete a save
|
||||
void delete_game(const std::string& name);
|
||||
|
||||
config& save_index();
|
||||
config& save_summary(const std::string& save);
|
||||
void delete_save_summary(const std::string& save);
|
||||
|
||||
void write_save_index();
|
||||
|
||||
void extract_summary_data_from_save(const game_state& state, config& out);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -547,7 +547,7 @@ SDL_Surface* getMinimap(int w, int h, const gamemap& map,
|
|||
|
||||
std::cerr << "scaling minimap..." << int(minimap) << "." << int(minimap->pixels) << "\n";
|
||||
|
||||
if(minimap->w != w || minimap->h != h) {
|
||||
if((minimap->w != w || minimap->h != h) && w != 0) {
|
||||
const scoped_sdl_surface surf(minimap);
|
||||
minimap = scale_surface(surf,w,h);
|
||||
}
|
||||
|
|
|
@ -210,6 +210,15 @@ gamemap::gamemap(const config& cfg, const std::string& data) : tiles_(1)
|
|||
const config::child_list& terrains = cfg.get_children("terrain");
|
||||
create_terrain_maps(terrains,terrainPrecedence_,letterToTerrain_,terrain_);
|
||||
|
||||
read(data);
|
||||
}
|
||||
|
||||
void gamemap::read(const std::string& data)
|
||||
{
|
||||
tiles_.clear();
|
||||
villages_.clear();
|
||||
std::fill(startingPositions_,startingPositions_+sizeof(startingPositions_)/sizeof(*startingPositions_),location());
|
||||
|
||||
size_t x = 0, y = 0;
|
||||
for(std::string::const_iterator i = data.begin(); i != data.end(); ++i) {
|
||||
char c = *i;
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
//one hex on the map. Starting locations are represented by numbers,
|
||||
//and will be of type keep.
|
||||
gamemap(const config& terrain_cfg, const std::string& data); //throw(incorrect_format_exception)
|
||||
void read(const std::string& data);
|
||||
|
||||
std::string write() const;
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ int mp_connect::load_map(const std::string& era, config& scenario_data, int num_
|
|||
//Load a saved game
|
||||
save_ = true;
|
||||
bool show_replay = false;
|
||||
const std::string game = dialogs::load_game_dialog(*disp_, &show_replay);
|
||||
const std::string game = dialogs::load_game_dialog(*disp_, *cfg_, *data_, &show_replay);
|
||||
if(game == "") {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1077,6 +1077,7 @@ void turn_info::cycle_units()
|
|||
for(++it; it != units_.end(); ++it) {
|
||||
if(it->second.side() == team_num_ &&
|
||||
unit_can_move(it->first,units_,map_,teams_) &&
|
||||
it->second.user_end_turn() == false &&
|
||||
!gui_.fogged(it->first.x,it->first.y)) {
|
||||
break;
|
||||
}
|
||||
|
@ -1087,6 +1088,7 @@ void turn_info::cycle_units()
|
|||
for(it = units_.begin(); it != units_.end(); ++it) {
|
||||
if(it->second.side() == team_num_ &&
|
||||
unit_can_move(it->first,units_,map_,teams_) &&
|
||||
it->second.user_end_turn() == false &&
|
||||
!gui_.fogged(it->first.x,it->first.y))
|
||||
break;
|
||||
}
|
||||
|
@ -1191,18 +1193,15 @@ void turn_info::end_unit_turn()
|
|||
const unit_map::iterator un = units_.find(selected_hex_);
|
||||
if(un != units_.end() && un->second.side() == team_num_ &&
|
||||
un->second.movement_left() >= 0) {
|
||||
std::vector<gamemap::location> steps;
|
||||
steps.push_back(selected_hex_);
|
||||
undo_stack_.push_back(undo_action(un->second,steps,un->second.movement_left(),-1));
|
||||
redo_stack_.clear();
|
||||
un->second.end_unit_turn();
|
||||
un->second.set_user_end_turn(!un->second.user_end_turn());
|
||||
gui_.draw_tile(selected_hex_.x,selected_hex_.y);
|
||||
|
||||
gui_.set_paths(NULL);
|
||||
current_paths_ = paths();
|
||||
recorder.add_movement(selected_hex_,selected_hex_);
|
||||
|
||||
cycle_units();
|
||||
if(un->second.user_end_turn()) {
|
||||
cycle_units();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1245,10 +1244,13 @@ void turn_info::undo()
|
|||
un.set_goto(gamemap::location());
|
||||
units_.erase(u);
|
||||
unit_display::move_unit(gui_,map_,route,un);
|
||||
|
||||
un.set_movement(starting_moves);
|
||||
units_.insert(std::pair<gamemap::location,unit>(route.back(),un));
|
||||
gui_.draw_tile(route.back().x,route.back().y);
|
||||
gui_.update_display();
|
||||
}
|
||||
|
||||
gui_.invalidate_unit();
|
||||
gui_.invalidate_game_status();
|
||||
|
||||
|
@ -1473,7 +1475,7 @@ void turn_info::save_game()
|
|||
void turn_info::load_game()
|
||||
{
|
||||
bool show_replay = false;
|
||||
const std::string game = dialogs::load_game_dialog(gui_,&show_replay);
|
||||
const std::string game = dialogs::load_game_dialog(gui_,terrain_config_,gameinfo_,&show_replay);
|
||||
if(game != "") {
|
||||
throw gamestatus::load_game_exception(game,show_replay);
|
||||
}
|
||||
|
|
|
@ -492,6 +492,32 @@ void set_show_haloes(bool value)
|
|||
prefs["show_haloes"] = value ? "yes" : "no";
|
||||
}
|
||||
|
||||
CACHE_SAVES_METHOD cache_saves()
|
||||
{
|
||||
if(prefs["cache_saves"] == "always") {
|
||||
return CACHE_SAVES_ALWAYS;
|
||||
} else if(prefs["cache_saves"] == "never") {
|
||||
return CACHE_SAVES_NEVER;
|
||||
} else {
|
||||
return CACHE_SAVES_ASK;
|
||||
}
|
||||
}
|
||||
|
||||
void set_cache_saves(CACHE_SAVES_METHOD method)
|
||||
{
|
||||
switch(method) {
|
||||
case CACHE_SAVES_ALWAYS:
|
||||
prefs["cache_saves"] = "always";
|
||||
break;
|
||||
case CACHE_SAVES_NEVER:
|
||||
prefs["cache_saves"] = "never";
|
||||
break;
|
||||
case CACHE_SAVES_ASK:
|
||||
prefs["cache_saves"] = "ask";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void show_preferences_dialog(display& disp)
|
||||
{
|
||||
const events::resize_lock prevent_resizing;
|
||||
|
|
|
@ -104,6 +104,10 @@ namespace preferences {
|
|||
bool show_haloes();
|
||||
void set_show_haloes(bool value);
|
||||
|
||||
enum CACHE_SAVES_METHOD { CACHE_SAVES_ASK, CACHE_SAVES_NEVER, CACHE_SAVES_ALWAYS };
|
||||
CACHE_SAVES_METHOD cache_saves();
|
||||
void set_cache_saves(CACHE_SAVES_METHOD method);
|
||||
|
||||
std::string client_type();
|
||||
|
||||
void set_theme(const std::string& theme);
|
||||
|
|
27
src/unit.cpp
27
src/unit.cpp
|
@ -48,8 +48,8 @@ bool compare_unit_values::operator()(const unit& a, const unit& b) const
|
|||
}
|
||||
|
||||
//constructor for reading a unit
|
||||
unit::unit(game_data& data, const config& cfg) : state_(STATE_NORMAL),
|
||||
moves_(0), facingLeft_(true),
|
||||
unit::unit(const game_data& data, const config& cfg) : state_(STATE_NORMAL),
|
||||
moves_(0), user_end_turn_(false), facingLeft_(true),
|
||||
recruit_(false),
|
||||
guardian_(false), upkeep_(UPKEEP_FREE)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ unit::unit(const unit_type* t, int side, bool use_traits, bool dummy_unit) :
|
|||
backupMaxHitpoints_(t->hitpoints()), experience_(0),
|
||||
maxExperience_(t->experience_needed()),
|
||||
backupMaxExperience_(t->experience_needed()),
|
||||
side_(side), moves_(0), facingLeft_(side != 1),
|
||||
side_(side), moves_(0), user_end_turn_(false), facingLeft_(side != 1),
|
||||
maxMovement_(t->movement()),
|
||||
backupMaxMovement_(t->movement()),
|
||||
recruit_(false), attacks_(t->attacks()),
|
||||
|
@ -92,7 +92,7 @@ unit::unit(const unit_type* t, const unit& u) :
|
|||
experience_(0),
|
||||
maxExperience_(t->experience_needed()),
|
||||
backupMaxExperience_(t->experience_needed()),
|
||||
side_(u.side()), moves_(u.moves_), facingLeft_(u.facingLeft_),
|
||||
side_(u.side()), moves_(u.moves_), user_end_turn_(false), facingLeft_(u.facingLeft_),
|
||||
maxMovement_(t->movement()),
|
||||
backupMaxMovement_(t->movement()),
|
||||
underlying_description_(u.underlying_description_),
|
||||
|
@ -233,9 +233,20 @@ bool unit::can_attack() const
|
|||
|
||||
void unit::set_movement(int moves)
|
||||
{
|
||||
user_end_turn_ = false;
|
||||
moves_ = moves;
|
||||
}
|
||||
|
||||
void unit::set_user_end_turn(bool value)
|
||||
{
|
||||
user_end_turn_ = value;
|
||||
}
|
||||
|
||||
bool unit::user_end_turn() const
|
||||
{
|
||||
return user_end_turn_;
|
||||
}
|
||||
|
||||
void unit::set_attacked()
|
||||
{
|
||||
moves_ = ATTACKED;
|
||||
|
@ -252,6 +263,7 @@ void unit::end_unit_turn()
|
|||
|
||||
void unit::new_turn()
|
||||
{
|
||||
user_end_turn_ = false;
|
||||
moves_ = total_movement();
|
||||
if(type().has_ability("ambush"))
|
||||
set_flag("ambush");
|
||||
|
@ -549,9 +561,9 @@ const std::vector<std::string>& unit::overlays() const
|
|||
return overlays_;
|
||||
}
|
||||
|
||||
void unit::read(game_data& data, const config& cfg)
|
||||
void unit::read(const game_data& data, const config& cfg)
|
||||
{
|
||||
std::map<std::string,unit_type>::iterator i = data.unit_types.find(cfg["type"]);
|
||||
std::map<std::string,unit_type>::const_iterator i = data.unit_types.find(cfg["type"]);
|
||||
if(i != data.unit_types.end())
|
||||
type_ = &i->second;
|
||||
else
|
||||
|
@ -583,8 +595,7 @@ void unit::read(game_data& data, const config& cfg)
|
|||
custom_unit_description_ = cfg["unit_description"];
|
||||
|
||||
traitsDescription_ = cfg["traits_description"];
|
||||
const std::map<std::string,std::string>::const_iterator recruit_itor =
|
||||
cfg.values.find("canrecruit");
|
||||
const std::map<std::string,std::string>::const_iterator recruit_itor = cfg.values.find("canrecruit");
|
||||
if(recruit_itor != cfg.values.end() && recruit_itor->second == "1") {
|
||||
recruit_ = true;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class unit
|
|||
public:
|
||||
friend struct unit_movement_resetter;
|
||||
|
||||
unit(game_data& data, const config& cfg);
|
||||
unit(const game_data& data, const config& cfg);
|
||||
unit(const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false);
|
||||
|
||||
//a constructor used when advancing a unit
|
||||
|
@ -58,6 +58,8 @@ public:
|
|||
bool can_recruit() const;
|
||||
int total_movement() const;
|
||||
int movement_left() const;
|
||||
void set_user_end_turn(bool value=true);
|
||||
bool user_end_turn() const;
|
||||
bool can_attack() const;
|
||||
void set_movement(int moves);
|
||||
void set_attacked();
|
||||
|
@ -92,7 +94,7 @@ public:
|
|||
void remove_overlay(const std::string& overlay);
|
||||
const std::vector<std::string>& overlays() const;
|
||||
|
||||
void read(game_data& data, const config& cfg);
|
||||
void read(const game_data& data, const config& cfg);
|
||||
|
||||
void write(config& cfg) const;
|
||||
|
||||
|
@ -161,6 +163,7 @@ private:
|
|||
// NOT_MOVED if not moved and pressed "end turn"
|
||||
enum MOVES { ATTACKED=-1, MOVED=-2, NOT_MOVED=-3 };
|
||||
int moves_;
|
||||
bool user_end_turn_;
|
||||
bool facingLeft_;
|
||||
int maxMovement_, backupMaxMovement_;
|
||||
bool resting_;
|
||||
|
|
43
src/widgets/progressbar.cpp
Normal file
43
src/widgets/progressbar.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "progressbar.hpp"
|
||||
|
||||
#include "../display.hpp"
|
||||
#include "../font.hpp"
|
||||
#include "../util.hpp"
|
||||
|
||||
namespace gui {
|
||||
|
||||
progress_bar::progress_bar(display& disp) : widget(disp), progress_(0)
|
||||
{}
|
||||
|
||||
void progress_bar::set_progress_percent(int progress)
|
||||
{
|
||||
progress_ = progress;
|
||||
set_dirty(true);
|
||||
}
|
||||
|
||||
void progress_bar::draw()
|
||||
{
|
||||
SDL_Surface* const surf = disp().video().getSurface();
|
||||
SDL_Rect area = location();
|
||||
|
||||
if(area.w >= 2 && area.h >= 2) {
|
||||
SDL_Rect inner_area = {area.x+1,area.y+1,area.w-2,area.h-2};
|
||||
SDL_FillRect(surf,&area,SDL_MapRGB(surf->format,0,0,0));
|
||||
SDL_FillRect(surf,&inner_area,SDL_MapRGB(surf->format,255,255,255));
|
||||
|
||||
inner_area.w = (inner_area.w*progress_)/100;
|
||||
SDL_FillRect(surf,&inner_area,SDL_MapRGB(surf->format,150,0,0));
|
||||
|
||||
const std::string text = str_cast(progress_) + "%";
|
||||
SDL_Rect text_area = font::text_area(text,14);
|
||||
|
||||
text_area.x = area.x + area.w/2 - text_area.w/2;
|
||||
text_area.y = area.y + area.h/2 - text_area.h/2;
|
||||
|
||||
font::draw_text(&disp(),location(),14,font::BLACK_COLOUR,text,text_area.x,text_area.y);
|
||||
}
|
||||
|
||||
update_rect(location());
|
||||
}
|
||||
|
||||
}
|
23
src/widgets/progressbar.hpp
Normal file
23
src/widgets/progressbar.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef PROGRESS_BAR_HPP_INCLUDED
|
||||
#define PROGRESS_BAR_HPP_INCLUDED
|
||||
|
||||
#include "widget.hpp"
|
||||
|
||||
namespace gui {
|
||||
|
||||
class progress_bar : public widget
|
||||
{
|
||||
public:
|
||||
progress_bar(display& disp);
|
||||
|
||||
void set_progress_percent(int progress);
|
||||
|
||||
void draw();
|
||||
|
||||
private:
|
||||
int progress_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue