added new 'load' dialog.

changed behavior of pressing 'space' to end a unit's turn
This commit is contained in:
Dave White 2004-06-10 00:35:45 +00:00
parent 7c941fa370
commit f0df140327
26 changed files with 499 additions and 48 deletions

View file

@ -67,6 +67,7 @@ Defeat:
side=1
canrecruit=1
controller=human
gold=200
[/side]
[side]

View file

@ -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]

View file

@ -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();

View file

@ -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)

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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";

View file

@ -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();

View file

@ -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)));
}
}

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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_;

View 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());
}
}

View 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