added animated on-map items. New attack dialog. New load game dialog

This commit is contained in:
Dave White 2004-06-10 23:43:25 +00:00
parent 6bd6f4a75e
commit 1949e00955
18 changed files with 656 additions and 279 deletions

View file

@ -62,7 +62,7 @@ Defeat:
side=2
canrecruit=1
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp,Saurian
{GOLD 40 120 180}
{GOLD 40 100 180}
enemy=1
[ai]
recruitment_pattern=scout,scout,fighter,fighter,archer

View file

@ -312,7 +312,7 @@ Defeat:
[message]
id=msg5_23
description=Delfador
message="During the reign of Garard I, your uncle's father, the dwarves of Knalga agreed to make the king a magnificent scepter. It took their finest smiths years to make it. But soon after it was completed, Orcs invaded the tunnels of Knalga. Now Knalga is in chaos, and, though some Dwarves still live in parts of it, at constant war with the Orcs, the Scepter was lost somewhere in the great caverns."
message="During the reign of Garard I, your grandfather, the dwarves of Knalga agreed to make the king a magnificent scepter. It took their finest smiths years to make it. But soon after it was completed, Orcs invaded the tunnels of Knalga. Now Knalga is in chaos, and, though some Dwarves still live in parts of it, at constant war with the Orcs, the Scepter was lost somewhere in the great caverns."
[/message]
[message]

View file

@ -630,6 +630,8 @@ see_also="See Also..."
attack_type="Attack Type"
attack_enemy="Attack Enemy"
attacks="attacks"
damage="damage"
hexes="hexes"

View file

@ -762,13 +762,13 @@ void ai_interface::attack_enemy(const location& u, const location& target, int w
attack(info_.disp,info_.map,info_.teams,u,target,weapon,info_.units,info_.state,info_.gameinfo,false);
check_victory(info_.units,info_.teams);
dialogs::advance_unit(info_.gameinfo,info_.units,u,info_.disp,true);
dialogs::advance_unit(info_.gameinfo,info_.map,info_.units,u,info_.disp,true);
const unit_map::const_iterator defender = info_.units.find(target);
if(defender != info_.units.end()) {
const size_t defender_team = size_t(defender->second.side()) - 1;
if(defender_team < info_.teams.size()) {
dialogs::advance_unit(info_.gameinfo,info_.units,target,info_.disp,!info_.teams[defender_team].is_human());
dialogs::advance_unit(info_.gameinfo,info_.map,info_.units,target,info_.disp,!info_.teams[defender_team].is_human());
}
}

View file

@ -14,6 +14,7 @@
#include "dialogs.hpp"
#include "events.hpp"
#include "font.hpp"
#include "game_config.hpp"
#include "language.hpp"
#include "log.hpp"
#include "preferences.hpp"
@ -34,6 +35,7 @@ namespace dialogs
{
void advance_unit(const game_data& info,
const gamemap& map,
std::map<gamemap::location,unit>& units,
gamemap::location loc,
display& gui, bool random_choice)
@ -62,9 +64,14 @@ void advance_unit(const game_data& info,
res = rand()%options.size();
} else if(options.size() > 1) {
const events::event_context dialog_events_context;
unit_preview_pane unit_preview(gui,&map,sample_units);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
res = gui::show_dialog(gui,NULL,string_table["advance_unit_heading"],
string_table["advance_unit_message"],
gui::OK_ONLY, &lang_options, &sample_units);
gui::OK_ONLY, &lang_options, &preview_panes);
}
recorder.choose_option(res);
@ -156,12 +163,13 @@ namespace {
class delete_save : public gui::dialog_button_action
{
public:
delete_save(display& disp, std::vector<save_info>& saves) : disp_(disp), saves_(saves) {}
delete_save(display& disp, std::vector<save_info>& saves, std::vector<config*>& save_summaries) : disp_(disp), saves_(saves), summaries_(save_summaries) {}
private:
gui::dialog_button_action::RESULT button_pressed(int menu_selection);
display& disp_;
std::vector<save_info>& saves_;
std::vector<config*>& summaries_;
};
gui::dialog_button_action::RESULT delete_save::button_pressed(int menu_selection)
@ -193,23 +201,173 @@ gui::dialog_button_action::RESULT delete_save::button_pressed(int menu_selection
//remove it from the list of saves
saves_.erase(saves_.begin() + index);
if(index < summaries_.size()) {
summaries_.erase(summaries_.begin() + index);
}
return gui::dialog_button_action::DELETE_ITEM;
} else {
return gui::dialog_button_action::NO_EFFECT;
}
}
static const SDL_Rect save_preview_pane_area = {-200,-400,200,400};
static const int save_preview_border = 10;
class save_preview_pane : public gui::preview_pane
{
public:
save_preview_pane(display& disp, const config& game_config, gamemap* map, const game_data& data,
const std::vector<save_info>& info, const std::vector<config*>& summaries)
: gui::preview_pane(disp), game_config_(&game_config), map_(map), data_(&data), info_(&info), summaries_(&summaries), index_(0)
{
set_location(save_preview_pane_area);
}
void draw();
void set_selection(int index) {
index_ = index;
set_dirty();
}
bool left_side() const { return true; }
private:
const config* game_config_;
gamemap* map_;
const game_data* data_;
const std::vector<save_info>* info_;
const std::vector<config*>* summaries_;
int index_;
std::map<std::string,shared_sdl_surface> map_cache_;
};
void save_preview_pane::draw()
{
if(!dirty()) {
return;
}
bg_restore();
if(index_ < 0 || index_ >= int(summaries_->size()) || info_->size() != summaries_->size()) {
return;
}
const config& summary = *(*summaries_)[index_];
SDL_Surface* const screen = disp().video().getSurface();
const SDL_Rect area = { location().x+save_preview_border, location().y+save_preview_border,
location().w-save_preview_border*2, location().h-save_preview_border*2 };
SDL_Rect clip_area = area;
const clip_rect_setter clipper(screen,clip_area);
int ypos = area.y;
const game_data::unit_type_map::const_iterator leader = data_->unit_types.find(summary["leader"]);
if(leader != data_->unit_types.end()) {
const scoped_sdl_surface image(image::get_image(leader->second.image(),image::UNSCALED));
if(image != NULL) {
SDL_Rect image_rect = {area.x,area.y,image->w,image->h};
ypos += image_rect.y + image_rect.h + save_preview_border;
SDL_BlitSurface(image,NULL,screen,&image_rect);
}
}
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";
}
}
}
}
SDL_Surface* map_surf = NULL;
if(map_data.empty() == false) {
const std::map<std::string,shared_sdl_surface>::const_iterator itor = map_cache_.find(map_data);
if(itor != map_cache_.end()) {
map_surf = itor->second;
} else if(map_ != NULL) {
try {
map_->read(map_data);
map_surf = image::getMinimap(100,100,*map_,0,NULL);
if(map_surf != NULL) {
map_cache_.insert(std::pair<std::string,shared_sdl_surface>(map_data,shared_sdl_surface(map_surf)));
}
} catch(gamemap::incorrect_format_exception&) {
}
}
}
if(map_surf != NULL) {
SDL_Rect map_rect = {area.x + area.w - map_surf->w,area.y,map_surf->w,map_surf->h};
ypos = maximum<int>(ypos,map_rect.y + map_rect.h + save_preview_border);
SDL_BlitSurface(map_surf,NULL,screen,&map_rect);
}
char time_buf[256];
const size_t res = strftime(time_buf,sizeof(time_buf),string_table["date_format"].c_str(),localtime(&((*info_)[index_].time_modified)));
if(res == 0) {
time_buf[0] = 0;
}
std::stringstream str;
// escape all special characters in filenames
std::string name = (*info_)[index_].name;
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"]);
}
font::draw_text(&disp(),area,12,font::NORMAL_COLOUR,str.str(),area.x,ypos,NULL,true);
}
} //end anon namespace
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();
delete_save save_deleter(disp,games);
gui::dialog_button delete_button(&save_deleter,string_table["delete_save"]);
std::vector<gui::dialog_button> buttons;
buttons.push_back(delete_button);
if(games.empty()) {
gui::show_dialog(disp,NULL,
string_table["no_saves_heading"],
@ -230,6 +388,11 @@ std::string load_game_dialog(display& disp, const config& game_config, const gam
summaries.push_back(&cfg);
}
delete_save save_deleter(disp,games,summaries);
gui::dialog_button delete_button(&save_deleter,string_table["delete_save"]);
std::vector<gui::dialog_button> buttons;
buttons.push_back(delete_button);
bool generate_summaries = !no_summary.empty();
//if there are more than 5 saves without a summary, it may take a substantial
@ -300,106 +463,20 @@ std::string load_game_dialog(display& disp, const config& game_config, const gam
write_save_index();
}
util::scoped_ptr<gamemap> map_ptr(NULL);
string_map map_cache;
std::vector<std::string> items;
for(i = games.begin(); i != games.end(); ++i) {
std::string name = i->name;
name.resize(minimum<size_t>(name.size(),40));
char time_buf[256];
const size_t res = strftime(time_buf,sizeof(time_buf),string_table["date_format"].c_str(),localtime(&(i->time_modified)));
if(res == 0)
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 << 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());
items.push_back(name);
}
gamemap map_obj(game_config,"");
std::vector<gui::preview_pane*> preview_panes;
save_preview_pane save_preview(disp,game_config,&map_obj,data,games,summaries);
preview_panes.push_back(&save_preview);
//create an option for whether the replay should be shown or not
std::vector<gui::check_item> options;
@ -409,7 +486,7 @@ std::string load_game_dialog(display& disp, const config& game_config, const gam
const int res = gui::show_dialog(disp,NULL,
string_table["load_game_heading"],
string_table["load_game_message"],
gui::OK_CANCEL,&items,NULL,"",NULL,NULL,&options,-1,-1,NULL,&buttons);
gui::OK_CANCEL,&items,&preview_panes,"",NULL,NULL,&options,-1,-1,NULL,&buttons);
if(res == -1)
return "";
@ -505,4 +582,254 @@ int show_file_chooser_dialog(display &disp, std::string &filename,
}
}
} //end namespace dialogs
namespace {
static const SDL_Rect unit_preview_size = {-150,-350,150,350};
static const int unit_preview_border = 10;
}
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const unit& u, bool on_left_side)
: gui::preview_pane(disp), details_button_(disp,string_table["action_describeunit"]),
map_(map), units_(&unit_store_), index_(0), left_(on_left_side)
{
set_location(unit_preview_size);
unit_store_.push_back(u);
}
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const std::vector<unit>& units, bool on_left_side)
: gui::preview_pane(disp), details_button_(disp,string_table["action_describeunit"]),
map_(map), units_(&units), index_(0), left_(on_left_side)
{
set_location(unit_preview_size);
}
bool unit_preview_pane::left_side() const
{
return left_;
}
void unit_preview_pane::set_selection(int index)
{
index = minimum<int>(int(units_->size()-1),index);
if(index != index_ && index >= 0) {
index_ = index;
set_dirty();
if(map_ != NULL) {
details_button_.set_dirty();
}
}
}
void unit_preview_pane::draw()
{
if(!dirty()) {
return;
}
bg_restore();
if(index_ < 0 || index_ >= int(units_->size())) {
return;
}
const unit& u = (*units_)[index_];
set_dirty(false);
SDL_Surface* const screen = disp().video().getSurface();
const SDL_Rect area = { location().x+unit_preview_border, location().y+unit_preview_border,
location().w-unit_preview_border*2, location().h-unit_preview_border*2 };
SDL_Rect clip_area = area;
const clip_rect_setter clipper(screen,clip_area);
scoped_sdl_surface unit_image(image::get_image(u.type().image(),image::UNSCALED));
if(left_side() == false && unit_image != NULL) {
unit_image.assign(image::reverse_image(unit_image));
}
if(unit_image != NULL) {
SDL_Rect image_rect = {area.x,area.y,unit_image->w,unit_image->h};
SDL_BlitSurface(unit_image,NULL,screen,&image_rect);
}
std::stringstream details;
details << font::BOLD_TEXT << u.description() << "\n"
<< font::BOLD_TEXT << u.type().language_name()
<< "\n" << font::SMALL_TEXT << "(" << string_table["level"] << " "
<< u.type().level() << ")\n"
<< translate_string(unit_type::alignment_description(u.type().alignment()))
<< "\n"
<< u.traits_description() << "\n";
const std::vector<std::string>& abilities = u.type().abilities();
for(std::vector<std::string>::const_iterator a = abilities.begin(); a != abilities.end(); ++a) {
details << translate_string_default("ability_" + *a, *a) << "\n";
}
//display in green/white/red depending on hitpoints
if(u.hitpoints() <= u.max_hitpoints()/3)
details << font::BAD_TEXT;
else if(u.hitpoints() > 2*(u.max_hitpoints()/3))
details << font::GOOD_TEXT;
details << string_table["hp"] << ": " << u.hitpoints()
<< "/" << u.max_hitpoints() << "\n";
if(u.type().advances_to().empty()) {
details << string_table["xp"] << ": " << u.experience() << "/-";
} else {
//if killing a unit the same level as us would level us up,
//then display in green
if(u.max_experience() - u.experience() < game_config::kill_experience) {
details << font::GOOD_TEXT;
}
details << string_table["xp"] << ": " << u.experience() << "/" << u.max_experience();
}
details << "\n"
<< string_table["moves"] << ": " << u.movement_left() << "/"
<< u.total_movement()
<< "\n";
const std::vector<attack_type>& attacks = u.attacks();
for(std::vector<attack_type>::const_iterator at_it = attacks.begin();
at_it != attacks.end(); ++at_it) {
const std::string& lang_weapon = string_table["weapon_name_" + at_it->name()];
const std::string& lang_type = string_table["weapon_type_" + at_it->type()];
const std::string& lang_special = string_table["weapon_special_" + at_it->special()];
details << "\n"
<< (lang_weapon.empty() ? at_it->name():lang_weapon) << " ("
<< (lang_type.empty() ? at_it->type():lang_type) << ")\n"
<< (lang_special.empty() ? at_it->special():lang_special)<<"\n"
<< at_it->damage() << "-" << at_it->num_attacks() << " -- "
<< (at_it->range() == attack_type::SHORT_RANGE ?
string_table["short_range"] :
string_table["long_range"]);
if(at_it->hexes() > 1) {
details << " (" << at_it->hexes() << ")";
}
details << "\n\n";
}
const SDL_Rect& text_area = font::draw_text(&disp(),area,12,font::NORMAL_COLOUR,details.str(),
area.x,area.y + (unit_image != NULL ? unit_image->h : 0) + unit_preview_border);
if(map_ != NULL) {
const SDL_Rect button_loc = {area.x + unit_preview_border,area.y + area.h - details_button_.location().h - unit_preview_border,
details_button_.location().w,details_button_.location().h};
details_button_.set_location(button_loc);
}
}
void unit_preview_pane::process()
{
if(map_ != NULL && details_button_.pressed() && index_ >= 0 && index_ < int(units_->size())) {
show_unit_description(disp(),*map_,(*units_)[index_]);
}
}
void show_unit_description(display& disp, const gamemap& map, const unit& u)
{
const std::string description = u.unit_description()
+ "\n\n" + string_table["see_also"];
std::vector<std::string> options;
options.push_back(string_table["terrain_info"]);
options.push_back(string_table["attack_resistance"]);
options.push_back(string_table["close_window"]);
const scoped_sdl_surface profile(image::get_image(u.type().image_profile(),image::SCALED));
const int res = gui::show_dialog(disp, profile, u.type().language_name(),
description,gui::MESSAGE, &options);
if(res == 0) {
show_unit_terrain_table(disp,map,u);
} else if(res == 1) {
show_unit_resistance(disp,u);
}
}
void show_unit_resistance(display& disp, const unit& u)
{
std::vector<std::string> items;
items.push_back(string_table["attack_type"] + "," + string_table["attack_resistance"]);
const std::map<std::string,std::string>& table = u.type().movement_type().damage_table();
for(std::map<std::string,std::string>::const_iterator i = table.begin(); i != table.end(); ++i) {
int resistance = 100 - atoi(i->second.c_str());
//if resistance is less than 0, display in red
const char prefix = resistance < 0 ? font::BAD_TEXT : font::NULL_MARKUP;
const std::string& lang_weapon = string_table["weapon_type_" + i->first];
const std::string& weap = lang_weapon.empty() ? i->first : lang_weapon;
std::stringstream str;
str << weap << "," << prefix << resistance << "%";
items.push_back(str.str());
}
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(disp,NULL,u);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
gui::show_dialog(disp,NULL,
u.type().language_name(),
string_table["unit_resistance_table"],
gui::MESSAGE,&items,&preview_panes);
}
void show_unit_terrain_table(display& disp, const gamemap& map, const unit& u)
{
std::vector<std::string> items;
items.push_back(string_table["terrain"] + "," +
string_table["movement"] + "," +
string_table["defense"]);
const unit_type& type = u.type();
const unit_movement_type& move_type = type.movement_type();
const std::vector<gamemap::TERRAIN>& terrains = map.get_terrain_precedence();
for(std::vector<gamemap::TERRAIN>::const_iterator t =
terrains.begin(); t != terrains.end(); ++t) {
//exclude fog and shroud
if(*t == gamemap::FOGGED || *t == gamemap::VOID_TERRAIN) {
continue;
}
const terrain_type& info = map.get_terrain_info(*t);
if(!info.is_alias()) {
const std::string& name = map.terrain_name(*t);
const std::string& lang_name = string_table[name];
const int moves = move_type.movement_cost(map,*t);
std::stringstream str;
str << lang_name << ",";
if(moves < 100)
str << moves;
else
str << "--";
const int defense = 100 - move_type.defense_modifier(map,*t);
str << "," << defense << "%";
items.push_back(str.str());
}
}
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(disp,NULL,u);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
gui::show_dialog(disp,NULL,u.type().language_name(),
string_table["terrain_info"],
gui::MESSAGE,&items,&preview_panes);
}
} //end namespace dialogs

View file

@ -16,9 +16,12 @@
#include "actions.hpp"
#include "config.hpp"
#include "display.hpp"
#include "map.hpp"
#include "show_dialog.hpp"
#include "unit.hpp"
#include "widgets/button.hpp"
namespace dialogs
{
//function to handle an advancing unit. If there is only one choice to advance
@ -28,7 +31,7 @@ namespace dialogs
//
//note that 'loc' is not a reference, because deleting an item from the units map
//(when replacing the unit that is being advanced) will possibly invalidate the reference
void advance_unit(const game_data& info,unit_map& units, gamemap::location loc,
void advance_unit(const game_data& info, const gamemap& map,unit_map& units, gamemap::location loc,
display& gui, bool random_choice=false);
bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::location loc, display& gui, size_t choice);
@ -57,6 +60,32 @@ void unit_speak(const config& message_info, display& disp, const unit_map& units
int show_file_chooser_dialog(display &displ, std::string &filename,
const std::string title="Choose a File",
int xloc=-1, int yloc=-1);
class unit_preview_pane : public gui::preview_pane
{
public:
unit_preview_pane(display& disp, const gamemap* map, const unit& u, bool left_side=true);
unit_preview_pane(display& disp, const gamemap* map, const std::vector<unit>& units, bool left_side=true);
bool left_side() const;
void set_selection(int index);
private:
void draw();
void process();
gui::button details_button_;
const gamemap* map_;
const std::vector<unit>* units_;
std::vector<unit> unit_store_;
int index_;
bool left_;
};
void show_unit_description(display& disp, const gamemap& map, const unit& u);
void show_unit_resistance(display& disp, const unit& u);
void show_unit_terrain_table(display& disp, const gamemap& map, const unit& u);
}
#endif

View file

@ -2089,14 +2089,23 @@ void display::invalidate_game_status()
invalidateGameStatus_ = true;
}
void display::add_overlay(const gamemap::location& loc, const std::string& img)
void display::add_overlay(const gamemap::location& loc, const std::string& img, const std::string& halo)
{
overlays_.insert(std::pair<gamemap::location,std::string>(loc,img));
halo_overlays_.insert(std::pair<gamemap::location,int>(loc,halo::add(get_location_x(loc)+hex_size()/2,get_location_y(loc)+hex_size()/2,halo)));
}
void display::remove_overlay(const gamemap::location& loc)
{
overlays_.erase(loc);
typedef std::multimap<gamemap::location,int>::const_iterator Itor;
std::pair<Itor,Itor> itors = halo_overlays_.equal_range(loc);
while(itors.first != itors.second) {
halo::remove(itors.first->second);
++itors.first;
}
halo_overlays_.erase(loc);
}
void display::write_overlays(config& cfg) const

View file

@ -224,7 +224,7 @@ public:
//functions to add and remove overlays from locations. An overlay is an
//image that is displayed on top of the tile. One tile may have multiple
//overlays. remove_overlay will remove all overlays on a tile.
void add_overlay(const gamemap::location& loc, const std::string& image);
void add_overlay(const gamemap::location& loc, const std::string& image, const std::string& halo="");
void remove_overlay(const gamemap::location& loc);
//function to serialize overlay data
@ -422,6 +422,7 @@ private:
bool invalidateGameStatus_;
std::multimap<gamemap::location,std::string> overlays_;
std::multimap<gamemap::location,int> halo_overlays_;
bool panelsDrawn_;

View file

@ -128,16 +128,20 @@ std::deque<context> event_contexts;
} //end anon namespace
event_context::event_context()
event_context::event_context(bool create) : create_(create)
{
event_contexts.push_back(context());
if(create_) {
event_contexts.push_back(context());
}
}
event_context::~event_context()
{
assert(event_contexts.empty() == false);
if(create_) {
assert(event_contexts.empty() == false);
event_contexts.pop_back();
event_contexts.pop_back();
}
}
handler::handler() : unicode_(SDL_EnableUNICODE(1))

View file

@ -61,8 +61,11 @@ bool has_focus(const handler* ptr);
//before their context is destroyed
struct event_context
{
event_context();
event_context(bool create=true);
~event_context();
private:
bool create_;
};
//causes events to be dispatched to all handler objects.

View file

@ -883,9 +883,12 @@ int play_game(int argc, char** argv)
defines_map["MEDIUM"] = preproc_define();
}
}
state.campaign_define = campaign["define"];
} else if(res == gui::MULTIPLAYER) {
state.campaign_type = "multiplayer";
state.scenario = "";
state.campaign_define = "MULTIPLAYER";
std::vector<std::string> host_or_join;
host_or_join.push_back(string_table["join_game"]);
@ -968,6 +971,10 @@ int play_game(int argc, char** argv)
continue;
}
if(state.campaign_define.empty() == false) {
defines_map[state.campaign_define] = preproc_define();
}
//make a new game config item based on the difficulty level
std::vector<line_source> line_src;
config game_config;

View file

@ -657,8 +657,9 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
else if(cmd == "item") {
gamemap::location loc(cfg);
const std::string& img = cfg["image"];
if(!img.empty()) {
screen->add_overlay(loc,img);
const std::string& halo = cfg["halo"];
if(!img.empty() || !halo.empty()) {
screen->add_overlay(loc,img,cfg["halo"]);
screen->draw_tile(loc.x,loc.y);
}
}

View file

@ -205,6 +205,8 @@ game_state read_game(const game_data& data, const config* cfg)
if(res.difficulty.empty())
res.difficulty = "NORMAL";
res.campaign_define = (*cfg)["campaign_define"];
res.campaign_type = (*cfg)["campaign_type"];
if(res.campaign_type.empty())
res.campaign_type = "scenario";
@ -272,6 +274,8 @@ void write_game(const game_state& game, config& cfg, WRITE_GAME_MODE mode)
cfg["difficulty"] = game.difficulty;
cfg["campaign_define"] = game.campaign_define;
cfg.add_child("variables",game.variables);
for(std::vector<unit>::const_iterator i = game.available_units.begin();

View file

@ -131,6 +131,8 @@ struct game_state
std::set<std::string> can_recruit; //units the player has the ability to recruit
std::string campaign_define; //if there is a define the campaign uses to customize data
//if the game is saved mid-level, we have a series of replay steps to
//take the game up to the position it was saved at.
config replay_data;

View file

@ -252,9 +252,6 @@ void gamemap::read(const std::string& data)
}
}
if(tiles_.empty())
throw incorrect_format_exception("empty map");
for(size_t n = 0; n != tiles_.size(); ++n) {
if(tiles_[n].size() != size_t(this->y())) {
std::cerr << "Map is not rectangular!\n";

View file

@ -576,8 +576,6 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
const std::vector<attack_type>& attacks = u->second.attacks();
std::vector<std::string> items;
std::vector<unit> units_list;
const int range = distance_between(u->first,enemy->first);
std::vector<int> attacks_in_range;
@ -642,7 +640,6 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
<< "%,&" << stats.back().defend_icon;
items.push_back(att.str());
units_list.push_back(enemy->second);
}
if (best_weapon_index >= 0) {
@ -659,10 +656,21 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
std::vector<gui::dialog_button> buttons;
buttons.push_back(gui::dialog_button(&calc_displayer,string_table["damage_calculations"]));
int res = gui::show_dialog(gui_,NULL,"",
string_table["choose_weapon"]+":\n",
gui::OK_CANCEL,&items,&units_list,"",NULL,NULL,NULL,-1,-1,
NULL,&buttons);
int res = 0;
{
const events::event_context dialog_events_context;
dialogs::unit_preview_pane attacker_preview(gui_,&map_,u->second,true);
dialogs::unit_preview_pane defender_preview(gui_,&map_,enemy->second,false);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&attacker_preview);
preview_panes.push_back(&defender_preview);
res = gui::show_dialog(gui_,NULL,string_table["attack_enemy"],
string_table["choose_weapon"]+":\n",
gui::OK_CANCEL,&items,&preview_panes,"",NULL,NULL,NULL,-1,-1,
NULL,&buttons);
}
cursor::set(cursor::NORMAL);
@ -701,13 +709,13 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
} catch(end_level_exception&) {
//if the level ends due to a unit being killed, still see if
//either the attacker or defender should advance
dialogs::advance_unit(gameinfo_,units_,selected_hex_,gui_);
dialogs::advance_unit(gameinfo_,units_,hex,gui_,!defender_human);
dialogs::advance_unit(gameinfo_,map_,units_,selected_hex_,gui_);
dialogs::advance_unit(gameinfo_,map_,units_,hex,gui_,!defender_human);
throw;
}
dialogs::advance_unit(gameinfo_,units_,selected_hex_,gui_);
dialogs::advance_unit(gameinfo_,units_,hex,gui_,!defender_human);
dialogs::advance_unit(gameinfo_,map_,units_,selected_hex_,gui_);
dialogs::advance_unit(gameinfo_,map_,units_,hex,gui_,!defender_human);
selected_hex_ = gamemap::location();
current_route_.steps.clear();
@ -1339,117 +1347,25 @@ void turn_info::terrain_table()
{
unit_map::const_iterator un = current_unit();
if(un == units_.end()) {
return;
if(un != units_.end()) {
dialogs::show_unit_terrain_table(gui_,map_,un->second);
}
gui_.draw();
std::vector<std::string> items;
items.push_back(string_table["terrain"] + "," +
string_table["movement"] + "," +
string_table["defense"]);
const unit_type& type = un->second.type();
const unit_movement_type& move_type = type.movement_type();
const std::vector<gamemap::TERRAIN>& terrains =
map_.get_terrain_precedence();
for(std::vector<gamemap::TERRAIN>::const_iterator t =
terrains.begin(); t != terrains.end(); ++t) {
//exclude fog and shroud
if(*t == gamemap::FOGGED || *t == gamemap::VOID_TERRAIN) {
continue;
}
const terrain_type& info = map_.get_terrain_info(*t);
if(!info.is_alias()) {
const std::string& name = map_.terrain_name(*t);
const std::string& lang_name = string_table[name];
const int moves = move_type.movement_cost(map_,*t);
std::stringstream str;
str << lang_name << ",";
if(moves < 100)
str << moves;
else
str << "--";
const int defense = 100 - move_type.defense_modifier(map_,*t);
str << "," << defense << "%";
items.push_back(str.str());
}
}
const std::vector<unit> units_list(items.size(),un->second);
const scoped_sdl_surface unit_image(image::get_image(un->second.type().image_profile(),image::UNSCALED));
gui::show_dialog(gui_,unit_image,un->second.type().language_name(),
string_table["terrain_info"],
gui::MESSAGE,&items,&units_list);
}
void turn_info::attack_resistance()
{
const unit_map::const_iterator un = current_unit();
if(un == units_.end())
return;
gui_.draw();
std::vector<std::string> items;
items.push_back(string_table["attack_type"] + "," +
string_table["attack_resistance"]);
const std::map<std::string,std::string>& table =
un->second.type().movement_type().damage_table();
for(std::map<std::string,std::string>::const_iterator i
= table.begin(); i != table.end(); ++i) {
int resistance = 100 - atoi(i->second.c_str());
//if resistance is less than 0, display in red
const char prefix = resistance < 0 ? font::BAD_TEXT : font::NULL_MARKUP;
const std::string& lang_weapon = string_table["weapon_type_" + i->first];
const std::string& weap = lang_weapon.empty() ? i->first : lang_weapon;
std::stringstream str;
str << weap << "," << prefix << resistance << "%";
items.push_back(str.str());
if(un != units_.end()) {
dialogs::show_unit_resistance(gui_,un->second);
}
const std::vector<unit> units_list(items.size(), un->second);
const scoped_sdl_surface unit_image(image::get_image(un->second.type().image_profile(),image::UNSCALED));
gui::show_dialog(gui_,unit_image,
un->second.type().language_name(),
string_table["unit_resistance_table"],
gui::MESSAGE,&items,&units_list);
}
void turn_info::unit_description()
{
const unit_map::const_iterator un = current_unit();
if(un == units_.end()) {
return;
}
const std::string description = un->second.unit_description()
+ "\n\n" + string_table["see_also"];
std::vector<std::string> options;
options.push_back(string_table["terrain_info"]);
options.push_back(string_table["attack_resistance"]);
options.push_back(string_table["close_window"]);
const scoped_sdl_surface unit_image(image::get_image(un->second.type().image_profile(), image::UNSCALED));
const int res = gui::show_dialog(gui_,unit_image,
un->second.type().language_name(),
description,gui::MESSAGE, &options);
if(res == 0) {
terrain_table();
} else if(res == 1) {
attack_resistance();
if(un != units_.end()) {
dialogs::show_unit_description(gui_,map_,un->second);
}
}
@ -1657,9 +1573,19 @@ void turn_info::recruit()
return;
}
const int recruit_res = gui::show_dialog(gui_,NULL,"",
string_table["recruit_unit"] + ":\n",
gui::OK_CANCEL,&items,&sample_units);
int recruit_res = 0;
{
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(gui_,&map_,sample_units);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
recruit_res = gui::show_dialog(gui_,NULL,"",
string_table["recruit_unit"] + ":\n",
gui::OK_CANCEL,&items,&preview_panes);
}
if(recruit_res != -1) {
do_recruit(item_keys[recruit_res]);
}
@ -1814,11 +1740,21 @@ void turn_info::recall()
std::vector<gui::dialog_button> buttons;
buttons.push_back(delete_button);
const int res = gui::show_dialog(gui_,NULL,"",
string_table["select_unit"] + ":\n",
gui::OK_CANCEL,&options,
&recall_list,"",NULL,
NULL,NULL,-1,-1,NULL,&buttons);
int res = 0;
{
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(gui_,&map_,recall_list);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
res = gui::show_dialog(gui_,NULL,"",
string_table["select_unit"] + ":\n",
gui::OK_CANCEL,&options,
&preview_panes,"",NULL,
NULL,NULL,-1,-1,NULL,&buttons);
}
if(res >= 0) {
unit& un = recall_list[res];
gamemap::location loc = last_hex_;
@ -1899,8 +1835,18 @@ void turn_info::create_unit()
unit_choices.back().new_turn();
}
const int choice = gui::show_dialog(gui_,NULL,"","Create unit (debug):",
gui::OK_CANCEL,&options,&unit_choices);
int choice = 0;
{
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(gui_,&map_,unit_choices);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
choice = gui::show_dialog(gui_,NULL,"","Create unit (debug):",
gui::OK_CANCEL,&options,&preview_panes);
}
if(choice >= 0 && choice < unit_choices.size()) {
units_.erase(last_hex_);
units_.insert(std::pair<gamemap::location,unit>(last_hex_,unit_choices[choice]));
@ -1967,8 +1913,18 @@ void turn_info::unit_list()
units_list.push_back(i->second);
}
const int selected = gui::show_dialog(gui_,NULL,string_table["unit_list"],"",
gui::OK_ONLY,&items,&units_list);
int selected = 0;
{
const events::event_context dialog_events_context;
dialogs::unit_preview_pane unit_preview(gui_,&map_,units_list);
std::vector<gui::preview_pane*> preview_panes;
preview_panes.push_back(&unit_preview);
selected = gui::show_dialog(gui_,NULL,string_table["unit_list"],"",
gui::OK_ONLY,&items,&preview_panes);
}
if(selected > 0 && selected < int(locations_list.size())) {
const gamemap::location& loc = locations_list[selected];
gui_.scroll_to_tile(loc.x,loc.y,display::WARP);

View file

@ -316,7 +316,7 @@ int show_dialog(display& disp, SDL_Surface* image,
const std::string& caption, const std::string& msg,
DIALOG_TYPE type,
const std::vector<std::string>* menu_items_ptr,
const std::vector<unit>* units_ptr,
const std::vector<preview_pane*>* preview_panes,
const std::string& text_widget_label,
std::string* text_widget_text,
dialog_action* action, std::vector<check_item>* options, int xloc, int yloc,
@ -327,7 +327,10 @@ int show_dialog(display& disp, SDL_Surface* image,
std::cerr << "showing dialog '" << caption << "' '" << msg << "'\n";
const events::event_context dialog_events_context;
//create the event context, but only activate it if we don't have preview panes.
//the presence of preview panes indicates that the caller will create the context,
//so that their preview panes may fall inside it.
const events::event_context dialog_events_context(preview_panes == NULL);
const dialog_manager manager;
const events::resize_lock prevent_resizing;
@ -335,9 +338,6 @@ int show_dialog(display& disp, SDL_Surface* image,
const std::vector<std::string>& menu_items =
(menu_items_ptr == NULL) ? std::vector<std::string>() : *menu_items_ptr;
const std::vector<unit> empty_units;
const std::vector<unit>& units = (units_ptr == NULL) ? empty_units : *units_ptr;
static const int message_font_size = 16;
static const int caption_font_size = 18;
@ -459,6 +459,19 @@ int show_dialog(display& disp, SDL_Surface* image,
}
}
size_t preview_pane_height = 0, left_preview_pane_width = 0, right_preview_pane_width = 0;
if(preview_panes != NULL) {
for(std::vector<preview_pane*>::const_iterator i = preview_panes->begin(); i != preview_panes->end(); ++i) {
const SDL_Rect& rect = (**i).location();
preview_pane_height = maximum<size_t>(rect.h,preview_pane_height);
if((**i).left_side()) {
left_preview_pane_width += rect.w;
} else {
right_preview_pane_width += rect.w;
}
}
}
const int left_padding = 10;
const int right_padding = 10;
const int image_h_padding = image != NULL ? 10 : 0;
@ -489,45 +502,62 @@ int show_dialog(display& disp, SDL_Surface* image,
padding_height + menu_.height() +
text_widget_height + check_button_height;
if(xloc <= -1 || yloc <= -1) {
xloc = scr->w/2 - total_width/2;
yloc = scr->h/2 - total_height/2;
}
int unitx = 0;
int unity = 0;
//if we are showing a dialog with unit details, then we have
//to make more room for it
if(!units.empty()) {
xloc += scr->w/10;
unitx = xloc - 300;
if(unitx < 10)
unitx = 10;
unity = yloc;
}
const int border_padding = 10;
const int frame_width = total_width + border_padding*2;
const int frame_height = total_height + border_padding*2;
int frame_width = total_width + border_padding*2;
int xframe = maximum<int>(0,xloc >= 0 ? xloc : scr->w/2 - (frame_width + left_preview_pane_width + right_preview_pane_width)/2);
const int frame_height = maximum<int>(int(preview_pane_height),total_height + border_padding*2);
if(xloc <= -1 || yloc <= -1) {
xloc = xframe + left_preview_pane_width;
yloc = scr->h/2 - frame_height/2;
}
if(xloc + frame_width > scr->w) {
xloc = scr->w - frame_width;
if(xloc < xframe) {
xframe = xloc;
}
}
if(yloc + frame_height > scr->h) {
yloc = scr->h - frame_height;
}
}
std::vector<button*> buttons_ptr;
for(std::vector<button>::iterator bt = buttons.begin(); bt != buttons.end(); ++bt) {
buttons_ptr.push_back(&*bt);
}
frame_width += left_preview_pane_width + right_preview_pane_width;
surface_restorer restorer;
const std::string& title = image == NULL ? caption : "";
draw_dialog(xloc,yloc,total_width,total_height,disp,title,dialog_style,&buttons_ptr,&restorer);
draw_dialog(xframe,yloc,frame_width,frame_height,disp,title,dialog_style,&buttons_ptr,&restorer);
//calculate the positions of the preview panes to the sides of the dialog
if(preview_panes != NULL) {
frame_width += left_preview_pane_width + right_preview_pane_width;
int left_preview_pane = xframe;
int right_preview_pane = xframe + total_width + left_preview_pane_width;
for(std::vector<preview_pane*>::const_iterator i = preview_panes->begin(); i != preview_panes->end(); ++i) {
SDL_Rect area = (**i).location();
area.y = yloc;
if((**i).left_side()) {
area.x = left_preview_pane;
left_preview_pane += area.w;
} else {
area.x = right_preview_pane;
right_preview_pane += area.w;
}
(**i).set_location(area);
}
}
const int menu_xpos = xloc+total_image_width+left_padding+image_h_padding;
const int menu_ypos = yloc+top_padding+text_and_image_height+menu_hpadding;
@ -664,16 +694,10 @@ int show_dialog(display& disp, SDL_Surface* image,
selection = 0;
}
if(size_t(selection) < units.size()) {
draw_dialog_frame(unitx,unity,unitw,unith,disp);
SDL_Rect clip_rect = { unitx, unity, unitw, unith };
disp.draw_unit_details(unitx+left_padding,
unity+top_padding+60, gamemap::location(), units[selection],
unit_details_rect, unitx+left_padding, unity+top_padding,
&clip_rect);
disp.update_display();
if(preview_panes != NULL) {
for(std::vector<preview_pane*>::const_iterator i = preview_panes->begin(); i != preview_panes->end(); ++i) {
(**i).set_selection(selection);
}
}
}
@ -682,7 +706,7 @@ int show_dialog(display& disp, SDL_Surface* image,
if(menu_.height() > 0) {
const int res = menu_.process(mousex,mousey,new_left_button,
!up_arrow && new_up_arrow,
!down_arrow && new_down_arrow,
!down_arrow && new_down_arrow,
!page_up && new_page_up,
!page_down && new_page_down,
select_item);

View file

@ -112,6 +112,17 @@ struct check_item {
bool checked;
};
//an interface for a 'preview pane'. A preview pane is shown beside a dialog created
//by 'show_dialog' and shows information about the selection.
class preview_pane : public widget {
public:
preview_pane(display& disp) : widget(disp) {}
virtual ~preview_pane() {}
virtual bool left_side() const = 0;
virtual void set_selection(int index) = 0;
};
//function to chop up one long string of text into lines
size_t text_to_lines(std::string& text, size_t max_length);
@ -122,7 +133,7 @@ int show_dialog(display& screen, SDL_Surface* image,
const std::string& caption, const std::string& message,
DIALOG_TYPE type=MESSAGE,
const std::vector<std::string>* menu_items=NULL,
const std::vector<unit>* units=NULL,
const std::vector<preview_pane*>* preview_panes=NULL,
const std::string& text_widget_label="",
std::string* text_widget_text=NULL,
dialog_action* action=NULL,