[[Terrain and calculations]]
- added cave-based terrain generator - added calculations for battles
This commit is contained in:
parent
834cac4b67
commit
1640dcd596
27 changed files with 395 additions and 77 deletions
|
@ -214,7 +214,7 @@ Defeat:
|
|||
[message]
|
||||
id=choice15e
|
||||
description=Kalenz
|
||||
message="We may take two paths which avoid the river. North, through the ancient home of my people, and then east to where they now live. Or we can go south, passing through the Swamps, before turning east, and then sorth. We would cross the river one time more if we chose that route, but I know a safe place for the crossing."
|
||||
message="We may take two paths which avoid the river. North, through the ancient home of my people, and then east to where they now live. Or we can go south, passing through the Swamps, before turning east, and then north. We would cross the river one time more if we chose that route, but I know a safe place for the crossing."
|
||||
[/message]
|
||||
[message]
|
||||
id=choice15f
|
||||
|
|
|
@ -104,8 +104,8 @@ Defeat:
|
|||
side=4
|
||||
canrecruit=1
|
||||
recruit=Elvish Fighter,Elvish Archer,Elvish Ranger,Elvish Scout,Elvish Hero,Elvish Marksman
|
||||
gold=200
|
||||
income=20
|
||||
gold=100
|
||||
income=10
|
||||
|
||||
#the Elves focus on getting to Konrad so they can
|
||||
#protect him
|
||||
|
|
|
@ -1,3 +1,52 @@
|
|||
[map_generator]
|
||||
name=cave
|
||||
map_width=50
|
||||
map_height=50
|
||||
[chamber]
|
||||
id=1
|
||||
size=6
|
||||
[items]
|
||||
[side]
|
||||
side=1
|
||||
[/side]
|
||||
[/items]
|
||||
[/chamber]
|
||||
[chamber]
|
||||
id=2
|
||||
size=20
|
||||
jagged=70
|
||||
[items]
|
||||
[side]
|
||||
side=2
|
||||
[/side]
|
||||
[/items]
|
||||
[passage]
|
||||
destination=1
|
||||
width=3
|
||||
jagged=50
|
||||
windiness=20
|
||||
[/passage]
|
||||
[/chamber]
|
||||
[chamber]
|
||||
id=3
|
||||
size=5
|
||||
[passage]
|
||||
destination=2
|
||||
width=2
|
||||
jagged=50
|
||||
windiness=8
|
||||
laziness=3
|
||||
[/passage]
|
||||
[passage]
|
||||
destination=1
|
||||
width=2
|
||||
jagged=50
|
||||
windiness=8
|
||||
laziness=5
|
||||
[/passage]
|
||||
[/chamber]
|
||||
[/map_generator]
|
||||
|
||||
[map_generator]
|
||||
name=default
|
||||
map_width=60
|
||||
|
|
|
@ -23,7 +23,7 @@ height=600
|
|||
[menu]
|
||||
title=main_menu
|
||||
image=lite
|
||||
items=speak,objectives,unitlist,recruit,recall,statustable,endturn,undo,redo,save,preferences,quit
|
||||
items=speak,objectives,unitlist,recruit,recall,statustable,endturn,undo,redo,save,statistics,preferences,quit
|
||||
rect=3,1,107,22
|
||||
xanchor=fixed
|
||||
yanchor=fixed
|
||||
|
|
|
@ -192,6 +192,15 @@ your_turn="It is now your turn"
|
|||
|
||||
leader="Leader"
|
||||
|
||||
#fighting statistics
|
||||
base_damage="base damage"
|
||||
minimum_damage="minimum damage"
|
||||
damage_calculations="Damage Calculations"
|
||||
attacker="Attacker"
|
||||
defender="Defender"
|
||||
attacker_resistance="attacker resistance vs"
|
||||
defender_resistance="defender resistance vs"
|
||||
|
||||
#buttons
|
||||
main_menu="Menu"
|
||||
game_menu="Game"
|
||||
|
|
|
@ -9,7 +9,7 @@ experience=500
|
|||
level=2
|
||||
alignment=neutral
|
||||
advanceto=null
|
||||
cost=50
|
||||
cost=40
|
||||
usage=scout
|
||||
unit_description="Half lion, half bird, these majestic creatures dominate the skies of the world. Since they are wary of other intelligent races, Gryphons should not be disturbed without a good reason."
|
||||
get_hit_sound=groan.wav
|
||||
|
|
111
src/actions.cpp
111
src/actions.cpp
|
@ -24,6 +24,7 @@
|
|||
#include "playturn.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
@ -235,11 +236,6 @@ battle_stats evaluate_battle_stats(
|
|||
if(res.attack_special == "backstab" && !backstab)
|
||||
res.attack_special = "";
|
||||
|
||||
//the leader is immune to being turned to stone
|
||||
if(d->second.can_recruit() && res.attack_special == "stone") {
|
||||
res.attack_special = "";
|
||||
}
|
||||
|
||||
res.range = (attack.range() == attack_type::SHORT_RANGE ?
|
||||
"Melee" : "Ranged");
|
||||
}
|
||||
|
@ -270,14 +266,51 @@ battle_stats evaluate_battle_stats(
|
|||
const int modifier = combat_modifier(state,units,d->first,d->second.type().alignment());
|
||||
res.damage_attacker_takes = (base_damage * (100+modifier))/100;
|
||||
|
||||
if(charge)
|
||||
if(include_strings) {
|
||||
std::stringstream str_base;
|
||||
str_base << string_table["base_damage"] << ", ," << defender_attacks[defend].damage();
|
||||
res.defend_calculations.push_back(str_base.str());
|
||||
|
||||
std::stringstream str_resist;
|
||||
|
||||
const int resist = a->second.type().movement_type().resistance_against(defender_attacks[defend]) - 100;
|
||||
str_resist << string_table["attacker_resistance"] << " " << translate_string(defender_attacks[defend].type())
|
||||
<< ",^" << (resist > 0 ? "+" : "") << resist << "%," << base_damage;
|
||||
res.defend_calculations.push_back(str_resist.str());
|
||||
|
||||
std::stringstream str_mod;
|
||||
const time_of_day& tod = timeofday_at(state,units,d->first);
|
||||
str_mod << translate_string_default(tod.id,tod.name) << ",^"
|
||||
<< (modifier > 0 ? "+" : "") << modifier << "%," << res.damage_attacker_takes;
|
||||
res.defend_calculations.push_back(str_mod.str());
|
||||
}
|
||||
|
||||
if(charge) {
|
||||
res.damage_attacker_takes *= 2;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("charge") << ",^+100%," << res.damage_attacker_takes;
|
||||
res.defend_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
if(under_leadership(units,defender))
|
||||
if(under_leadership(units,defender)) {
|
||||
res.damage_attacker_takes += res.damage_attacker_takes/8 + 1;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("leadership") << ",^+12.5%," << res.damage_attacker_takes;
|
||||
res.defend_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
if(res.damage_attacker_takes < 1)
|
||||
if(res.damage_attacker_takes < 1) {
|
||||
res.damage_attacker_takes = 1;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("minimum_damage") << ", ,1";
|
||||
res.defend_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
res.ndefends = defender_attacks[defend].num_attacks();
|
||||
|
||||
|
@ -287,10 +320,6 @@ battle_stats evaluate_battle_stats(
|
|||
if(include_strings) {
|
||||
res.defend_special = defender_attacks[defend].special();
|
||||
res.defend_icon = defender_attacks[defend].icon();
|
||||
|
||||
//leaders are immune to being turned to stone
|
||||
if(a->second.can_recruit() && res.defend_special == "stone")
|
||||
res.defend_special = "";
|
||||
}
|
||||
|
||||
//if the defender drains, and the attacker is a living creature, then
|
||||
|
@ -315,11 +344,54 @@ battle_stats evaluate_battle_stats(
|
|||
|
||||
const int base_damage = d->second.damage_against(attack);
|
||||
const int modifier = combat_modifier(state,units,a->first,a->second.type().alignment());
|
||||
res.damage_defender_takes = ((base_damage * (100 + modifier))/100)
|
||||
* (charge ? 2 : 1) * (backstab ? 2 : 1);
|
||||
res.damage_defender_takes = ((base_damage * (100 + modifier))/100);
|
||||
|
||||
if(under_leadership(units,attacker))
|
||||
if(include_strings) {
|
||||
std::stringstream str_base;
|
||||
|
||||
str_base << string_table["base_damage"] << ", ," << attack.damage();
|
||||
res.attack_calculations.push_back(str_base.str());
|
||||
|
||||
std::stringstream str_resist;
|
||||
|
||||
const int resist = d->second.type().movement_type().resistance_against(attack) - 100;
|
||||
str_resist << string_table["defender_resistance"] << " " << translate_string(attack.type())
|
||||
<< ",^" << (resist > 0 ? "+" : "") << resist << "%," << base_damage;
|
||||
res.attack_calculations.push_back(str_resist.str());
|
||||
|
||||
std::stringstream str_mod;
|
||||
const time_of_day& tod = timeofday_at(state,units,a->first);
|
||||
str_mod << translate_string_default(tod.id,tod.name) << ",^"
|
||||
<< (modifier > 0 ? "+" : "") << modifier << "%," << res.damage_defender_takes;
|
||||
res.attack_calculations.push_back(str_mod.str());
|
||||
}
|
||||
|
||||
if(charge) {
|
||||
res.damage_defender_takes *= 2;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("charge") << ",^+100%," << res.damage_defender_takes;
|
||||
res.attack_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
if(backstab) {
|
||||
res.damage_defender_takes *= 2;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("backstab") << ",^+100%," << res.damage_defender_takes;
|
||||
res.attack_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
if(under_leadership(units,attacker)) {
|
||||
res.damage_defender_takes += res.damage_defender_takes/8 + 1;
|
||||
if(include_strings) {
|
||||
std::stringstream str;
|
||||
str << translate_string("leadership") << ",^+12.5%," << res.damage_defender_takes;
|
||||
res.attack_calculations.push_back(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
//if the attacker drains, and the defender is a living creature, then
|
||||
//the attacker will drain for half the damage it does
|
||||
|
@ -348,7 +420,6 @@ void attack(display& gui, const gamemap& map,
|
|||
const gamestatus& state,
|
||||
const game_data& info, bool player_is_attacker)
|
||||
{
|
||||
|
||||
//stop the user from issuing any commands while the units are fighting
|
||||
const command_disabler disable_commands;
|
||||
|
||||
|
@ -373,6 +444,8 @@ void attack(display& gui, const gamemap& map,
|
|||
battle_stats stats = evaluate_battle_stats(map,attacker,defender,
|
||||
attack_with,units,state,info);
|
||||
|
||||
statistics::attack_context attack_stats(a->second,d->second,stats);
|
||||
|
||||
static const std::string poison_string("poison");
|
||||
|
||||
while(stats.nattacks > 0 || stats.ndefends > 0) {
|
||||
|
@ -415,6 +488,9 @@ void attack(display& gui, const gamemap& map,
|
|||
hits ? stats.damage_defender_takes : 0,
|
||||
a->second.attacks()[attack_with]);
|
||||
|
||||
attack_stats.attack_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS)
|
||||
: statistics::attack_context::MISSES);
|
||||
|
||||
if(ran_results == NULL) {
|
||||
config cfg;
|
||||
cfg["hits"] = (hits ? "yes" : "no");
|
||||
|
@ -541,6 +617,9 @@ void attack(display& gui, const gamemap& map,
|
|||
hits ? stats.damage_attacker_takes : 0,
|
||||
d->second.attacks()[stats.defend_with]);
|
||||
|
||||
attack_stats.defend_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS)
|
||||
: statistics::attack_context::MISSES);
|
||||
|
||||
if(ran_results == NULL) {
|
||||
config cfg;
|
||||
cfg["hits"] = (hits ? "yes" : "no");
|
||||
|
|
|
@ -58,6 +58,7 @@ struct battle_stats
|
|||
int ndefends, nattacks;
|
||||
int attack_with, defend_with;
|
||||
bool attacker_plague, defender_plague;
|
||||
std::vector<std::string> attack_calculations, defend_calculations;
|
||||
};
|
||||
|
||||
//evaluate_battle_stats: a function which, if given an attacker
|
||||
|
|
|
@ -127,8 +127,7 @@ struct config
|
|||
typedef std::vector<config*>::const_iterator const_child_iterator;
|
||||
|
||||
typedef std::pair<child_iterator,child_iterator> child_itors;
|
||||
typedef std::pair<const_child_iterator,const_child_iterator>
|
||||
const_child_itors;
|
||||
typedef std::pair<const_child_iterator,const_child_iterator> const_child_itors;
|
||||
|
||||
child_itors child_range(const std::string& key);
|
||||
const_child_itors child_range(const std::string& key) const;
|
||||
|
|
|
@ -739,6 +739,11 @@ void display::draw_report(reports::TYPE report_num)
|
|||
for(std::vector<std::string>::const_iterator col = cols.begin(); col != cols.end(); ++col) {
|
||||
SDL_Rect clip_rect = rect;
|
||||
scoped_sdl_surface image(image::get_image(*col,image::UNSCALED));
|
||||
if(image == NULL) {
|
||||
std::cerr << "could not find image for report: '" << *col << "'\n";
|
||||
return;
|
||||
}
|
||||
|
||||
blit_surface(x,y,image,NULL,&clip_rect);
|
||||
if(image->h > tallest_image)
|
||||
tallest_image = image->h;
|
||||
|
|
|
@ -277,6 +277,8 @@ public:
|
|||
|
||||
const theme::menu* menu_pressed(int mousex, int mousey, bool button_pressed);
|
||||
|
||||
void unit_die(const gamemap::location& loc, SDL_Surface* image=NULL);
|
||||
|
||||
private:
|
||||
display(const display&);
|
||||
void operator=(const display&);
|
||||
|
@ -299,8 +301,6 @@ private:
|
|||
bool reverse, bool upside_down=false,
|
||||
double alpha=1.0, Uint32 blendto=0, double submerged=0.0);
|
||||
|
||||
void unit_die(const gamemap::location& loc, SDL_Surface* image=NULL);
|
||||
|
||||
bool unit_attack_ranged(const gamemap::location& a,
|
||||
const gamemap::location& b,
|
||||
int damage, const attack_type& attack);
|
||||
|
|
|
@ -830,6 +830,11 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
|
|||
for(std::map<gamemap::location,unit>::iterator un = units->begin();
|
||||
un != units->end(); ++un) {
|
||||
while(un != units->end() && game_events::unit_matches_filter(un,cfg)) {
|
||||
if(cfg["animate"] == "yes") {
|
||||
screen->scroll_to_tile(un->first.x,un->first.y,display::WARP);
|
||||
screen->unit_die(un->first);
|
||||
}
|
||||
|
||||
units->erase(un);
|
||||
un = units->begin();
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
|
|||
m.insert(val("preferences",HOTKEY_PREFERENCES));
|
||||
m.insert(val("objectives",HOTKEY_OBJECTIVES));
|
||||
m.insert(val("unitlist",HOTKEY_UNIT_LIST));
|
||||
m.insert(val("statistics",HOTKEY_STATISTICS));
|
||||
m.insert(val("quit",HOTKEY_QUIT_GAME));
|
||||
}
|
||||
|
||||
|
@ -348,6 +349,10 @@ void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* ex
|
|||
if(executor)
|
||||
executor->unit_list();
|
||||
break;
|
||||
case HOTKEY_STATISTICS:
|
||||
if(executor)
|
||||
executor->show_statistics();
|
||||
break;
|
||||
case HOTKEY_QUIT_GAME: {
|
||||
const int res = gui::show_dialog(disp,NULL,"",string_table["quit_message"],gui::YES_NO);
|
||||
if(res == 0) {
|
||||
|
|
|
@ -32,7 +32,7 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
|
|||
HOTKEY_RECRUIT, HOTKEY_REPEAT_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
|
||||
HOTKEY_TOGGLE_GRID, HOTKEY_STATUS_TABLE, HOTKEY_MUTE,
|
||||
HOTKEY_SPEAK, HOTKEY_CREATE_UNIT, HOTKEY_PREFERENCES,
|
||||
HOTKEY_OBJECTIVES, HOTKEY_UNIT_LIST, HOTKEY_QUIT_GAME,
|
||||
HOTKEY_OBJECTIVES, HOTKEY_UNIT_LIST, HOTKEY_STATISTICS, HOTKEY_QUIT_GAME,
|
||||
HOTKEY_NULL };
|
||||
|
||||
struct hotkey_item {
|
||||
|
@ -96,6 +96,7 @@ public:
|
|||
virtual void preferences() = 0;
|
||||
virtual void objectives() = 0;
|
||||
virtual void unit_list() = 0;
|
||||
virtual void show_statistics() = 0;
|
||||
|
||||
virtual bool can_execute_command(HOTKEY_COMMAND command) const = 0;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <ctime>
|
||||
#include <vector>
|
||||
|
||||
#include "cavegen.hpp"
|
||||
#include "mapgen.hpp"
|
||||
#include "mapgen_dialog.hpp"
|
||||
#include "pathfind.hpp"
|
||||
|
@ -31,6 +32,29 @@ std::string random_generate_map(const std::string& parms)
|
|||
return generator->create_map(parameters);
|
||||
}
|
||||
|
||||
config random_generate_scenario(const std::string& parms)
|
||||
{
|
||||
//the first token is the name of the generator, tokens after
|
||||
//that are arguments to the generator
|
||||
std::vector<std::string> parameters = config::split(parms,' ');
|
||||
map_generator* const generator = get_map_generator(parameters.front());
|
||||
if(generator == NULL) {
|
||||
std::cerr << "could not find map generator '" << parameters.front() << "'\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
parameters.erase(parameters.begin());
|
||||
return generator->create_scenario(parameters);
|
||||
}
|
||||
|
||||
config map_generator::create_scenario(const std::vector<std::string>& args)
|
||||
{
|
||||
config res;
|
||||
config& item = res.add_child("scenario");
|
||||
item.values["map_data"] = create_map(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::vector<std::vector<int> > height_map;
|
||||
|
@ -778,9 +802,12 @@ generator_map generators;
|
|||
|
||||
map_generator::manager::manager(const config& game_config)
|
||||
{
|
||||
map_generator* const gen = new default_map_generator(game_config);
|
||||
map_generator* gen = new default_map_generator(game_config);
|
||||
assert(generators.count(gen->name()) == 0);
|
||||
generators[gen->name()] = gen;
|
||||
|
||||
gen = new cave_map_generator(game_config);
|
||||
generators[gen->name()] = gen;
|
||||
}
|
||||
|
||||
map_generator::manager::~manager()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
|
||||
std::string random_generate_map(const std::string& parms);
|
||||
config random_generate_scenario(const std::string& parms);
|
||||
|
||||
class map_generator
|
||||
{
|
||||
|
@ -27,7 +28,9 @@ public:
|
|||
|
||||
//creates a new map and returns it. args may contain arguments to
|
||||
//the map generator
|
||||
virtual std::string create_map(const std::vector<std::string>& args) const = 0;
|
||||
virtual std::string create_map(const std::vector<std::string>& args) = 0;
|
||||
|
||||
virtual config create_scenario(const std::vector<std::string>& args);
|
||||
|
||||
struct manager
|
||||
{
|
||||
|
|
|
@ -229,7 +229,7 @@ void default_map_generator::user_config(display& disp)
|
|||
|
||||
std::string default_map_generator::name() const { return "default"; }
|
||||
|
||||
std::string default_map_generator::create_map(const std::vector<std::string>& args) const
|
||||
std::string default_map_generator::create_map(const std::vector<std::string>& args)
|
||||
{
|
||||
if(cfg_ != NULL)
|
||||
return default_generate_map(width_,height_,iterations_,hill_size_,max_lakes_,nvillages_,nplayers_,*cfg_);
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
|
||||
std::string name() const;
|
||||
|
||||
std::string create_map(const std::vector<std::string>& args) const;
|
||||
std::string create_map(const std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
size_t width_, height_, iterations_, hill_size_, max_lakes_, nvillages_, nplayers_;
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
return GAME_CANCELLED;
|
||||
} else {
|
||||
sides_ = reply;
|
||||
std::cerr << "got some sides. Current number of sides = " << sides_.get_children("side").size() << "," << reply.get_children("side").size() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -560,10 +560,7 @@ redo_turn:
|
|||
string_table["defeat_message"],
|
||||
gui::OK_ONLY);
|
||||
return DEFEAT;
|
||||
} else if(end_level.result == CONTINUE) {
|
||||
//basically like a victory but without all the celebrations
|
||||
return VICTORY;
|
||||
} else if(end_level.result == VICTORY) {
|
||||
} else if(end_level.result == VICTORY || end_level.result == CONTINUE) {
|
||||
try {
|
||||
game_events::fire("victory");
|
||||
} catch(end_level_exception&) {
|
||||
|
@ -578,6 +575,12 @@ redo_turn:
|
|||
}
|
||||
}
|
||||
|
||||
//'continue' is like a victory, except it doesn't announce victory,
|
||||
//and the player returns 100% of gold.
|
||||
if(end_level.result == CONTINUE) {
|
||||
state_of_game.gold = teams[0].gold();
|
||||
}
|
||||
|
||||
if((*level)["disallow_recall"] == "yes") {
|
||||
return VICTORY;
|
||||
}
|
||||
|
|
125
src/playturn.cpp
125
src/playturn.cpp
|
@ -24,6 +24,7 @@
|
|||
#include "preferences.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
|
@ -411,6 +412,62 @@ void turn_info::mouse_press(const SDL_MouseButtonEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
//a class which, when a button is pressed, will display
|
||||
//how an attack was calculated
|
||||
namespace {
|
||||
class attack_calculations_displayer : public gui::dialog_button_action
|
||||
{
|
||||
public:
|
||||
attack_calculations_displayer(display& disp, std::vector<battle_stats>& stats)
|
||||
: disp_(disp), stats_(stats)
|
||||
{}
|
||||
|
||||
void button_pressed(int selection);
|
||||
private:
|
||||
display& disp_;
|
||||
std::vector<battle_stats>& stats_;
|
||||
};
|
||||
|
||||
void attack_calculations_displayer::button_pressed(int selection)
|
||||
{
|
||||
const size_t index = size_t(selection);
|
||||
if(index < stats_.size()) {
|
||||
const battle_stats& stats = stats_[index];
|
||||
std::vector<std::string> calcs;
|
||||
|
||||
std::stringstream str;
|
||||
str << string_table["attacker"] << ", , ,";
|
||||
if(stats.defend_calculations.empty() == false) {
|
||||
str << string_table["defender"];
|
||||
}
|
||||
|
||||
calcs.push_back(str.str());
|
||||
|
||||
for(size_t i = 0; i < maximum<size_t>(stats.attack_calculations.size(),stats.defend_calculations.size()); ++i) {
|
||||
std::stringstream str;
|
||||
if(i < stats.attack_calculations.size() && stats.attack_calculations.empty() == false) {
|
||||
str << stats.attack_calculations[i];
|
||||
} else {
|
||||
str << ", , ";
|
||||
}
|
||||
|
||||
str << ",";
|
||||
|
||||
if(i < stats.defend_calculations.size() && stats.defend_calculations.empty() == false) {
|
||||
str << stats.defend_calculations[i];
|
||||
} else {
|
||||
str << " , , ";
|
||||
}
|
||||
|
||||
calcs.push_back(str.str());
|
||||
}
|
||||
|
||||
gui::show_dialog(disp_,NULL,"",string_table["damage_calculations"],gui::OK_ONLY,&calcs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
||||
{
|
||||
const team& current_team = teams_[team_num_-1];
|
||||
|
@ -443,8 +500,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
route = enemy_paths_ ? current_paths_.routes.end() :
|
||||
current_paths_.routes.find(hex);
|
||||
|
||||
unit_map::iterator enemy = find_visible_unit(units_,
|
||||
hex, map_,
|
||||
unit_map::iterator enemy = find_visible_unit(units_, hex, map_,
|
||||
status_.get_time_of_day().lawful_bonus,teams_,current_team);
|
||||
|
||||
//see if we're trying to attack an enemy
|
||||
|
@ -464,18 +520,20 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
int best_weapon_index = -1;
|
||||
int best_weapon_rating = 0;
|
||||
|
||||
std::vector<battle_stats> stats;
|
||||
|
||||
for(size_t a = 0; a != attacks.size(); ++a) {
|
||||
if(attacks[a].hexes() < range)
|
||||
continue;
|
||||
|
||||
attacks_in_range.push_back(a);
|
||||
|
||||
const battle_stats stats = evaluate_battle_stats(
|
||||
stats.push_back(evaluate_battle_stats(
|
||||
map_,selected_hex_,hex,
|
||||
a,units_,status_,gameinfo_);
|
||||
a,units_,status_,gameinfo_));
|
||||
|
||||
int weapon_rating = stats.chance_to_hit_defender *
|
||||
stats.damage_defender_takes * stats.nattacks;
|
||||
int weapon_rating = stats.back().chance_to_hit_defender *
|
||||
stats.back().damage_defender_takes * stats.back().nattacks;
|
||||
|
||||
if (best_weapon_index < 0 || best_weapon_rating < weapon_rating) {
|
||||
best_weapon_index = items.size();
|
||||
|
@ -483,42 +541,41 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
}
|
||||
|
||||
const std::string& lang_attack_name =
|
||||
string_table["weapon_name_"+stats.attack_name];
|
||||
string_table["weapon_name_"+stats.back().attack_name];
|
||||
const std::string& lang_attack_type =
|
||||
string_table["weapon_type_"+stats.attack_type];
|
||||
string_table["weapon_type_"+stats.back().attack_type];
|
||||
const std::string& lang_range =
|
||||
string_table[stats.range == "Melee" ?
|
||||
string_table[stats.back().range == "Melee" ?
|
||||
"short_range" : "long_range"];
|
||||
|
||||
const std::string& lang_defend_name =
|
||||
string_table["weapon_name_"+stats.defend_name];
|
||||
string_table["weapon_name_"+stats.back().defend_name];
|
||||
const std::string& lang_defend_type =
|
||||
string_table["weapon_type_"+stats.defend_type];
|
||||
string_table["weapon_type_"+stats.back().defend_type];
|
||||
|
||||
const std::string& attack_name = lang_attack_name.empty() ?
|
||||
stats.attack_name : lang_attack_name;
|
||||
stats.back().attack_name : lang_attack_name;
|
||||
const std::string& attack_type = lang_attack_type.empty() ?
|
||||
stats.attack_type : lang_attack_type;
|
||||
stats.back().attack_type : lang_attack_type;
|
||||
const std::string& defend_name = lang_defend_name.empty() ?
|
||||
stats.defend_name : lang_defend_name;
|
||||
stats.back().defend_name : lang_defend_name;
|
||||
const std::string& defend_type = lang_defend_type.empty() ?
|
||||
stats.defend_type : lang_defend_type;
|
||||
stats.back().defend_type : lang_defend_type;
|
||||
|
||||
const std::string& range = lang_range.empty() ?
|
||||
stats.range : lang_range;
|
||||
stats.back().range : lang_range;
|
||||
|
||||
std::stringstream att;
|
||||
att << "&" << stats.attack_icon << "," << attack_name
|
||||
<< " " << stats.damage_defender_takes << "-"
|
||||
<< stats.nattacks << " " << range << " "
|
||||
<< stats.chance_to_hit_defender
|
||||
<< "%";
|
||||
att << "&" << stats.back().attack_icon << "," << attack_name
|
||||
<< " " << stats.back().damage_defender_takes << "-"
|
||||
<< stats.back().nattacks << " " << range << " "
|
||||
<< stats.back().chance_to_hit_defender << "%";
|
||||
|
||||
att << "," << string_table["versus"] << ",";
|
||||
att << defend_name << " " << stats.damage_attacker_takes << "-"
|
||||
<< stats.ndefends << " "
|
||||
<< stats.chance_to_hit_attacker
|
||||
<< "%,&" << stats.defend_icon;
|
||||
att << defend_name << " " << stats.back().damage_attacker_takes << "-"
|
||||
<< stats.back().ndefends << " "
|
||||
<< stats.back().chance_to_hit_attacker
|
||||
<< "%,&" << stats.back().defend_icon;
|
||||
|
||||
items.push_back(att.str());
|
||||
units_list.push_back(enemy->second);
|
||||
|
@ -534,9 +591,14 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
|
|||
gui_.highlight_hex(gamemap::location());
|
||||
gui_.draw(true,true);
|
||||
|
||||
attack_calculations_displayer calc_displayer(gui_,stats);
|
||||
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);
|
||||
gui::OK_CANCEL,&items,&units_list,"",NULL,NULL,NULL,-1,-1,
|
||||
NULL,&buttons);
|
||||
|
||||
if(size_t(res) < attacks_in_range.size()) {
|
||||
res = attacks_in_range[res];
|
||||
|
@ -726,11 +788,12 @@ bool turn_info::can_execute_command(hotkey::HOTKEY_COMMAND command) const
|
|||
case hotkey::HOTKEY_PREFERENCES:
|
||||
case hotkey::HOTKEY_OBJECTIVES:
|
||||
case hotkey::HOTKEY_UNIT_LIST:
|
||||
case hotkey::HOTKEY_STATISTICS:
|
||||
case hotkey::HOTKEY_QUIT_GAME:
|
||||
return true;
|
||||
|
||||
case hotkey::HOTKEY_SPEAK:
|
||||
return !browse_ && network::nconnections() > 0;
|
||||
return network::nconnections() > 0;
|
||||
|
||||
case hotkey::HOTKEY_REDO:
|
||||
return !browse_ && !redo_stack_.empty();
|
||||
|
@ -1569,6 +1632,14 @@ void turn_info::unit_list()
|
|||
}
|
||||
}
|
||||
|
||||
void turn_info::show_statistics()
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "Kills: " << statistics::calculate_stats(0,team_num_).killed.size() << "\n"
|
||||
<< "Deaths: " << statistics::calculate_stats(0,team_num_).deaths.size() << "\n";
|
||||
gui::show_dialog(gui_,NULL,"",str.str(),gui::OK_ONLY);
|
||||
}
|
||||
|
||||
unit_map::iterator turn_info::current_unit()
|
||||
{
|
||||
unit_map::iterator i = units_.end();
|
||||
|
|
|
@ -98,6 +98,7 @@ private:
|
|||
void preferences();
|
||||
void objectives();
|
||||
void unit_list();
|
||||
void show_statistics();
|
||||
|
||||
void do_recruit(const std::string& name);
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ int show_dialog(display& disp, SDL_Surface* image,
|
|||
const std::string& text_widget_label,
|
||||
std::string* text_widget_text,
|
||||
dialog_action* action, std::vector<check_item>* options, int xloc, int yloc,
|
||||
const std::string* dialog_style)
|
||||
const std::string* dialog_style, std::vector<dialog_button>* action_buttons)
|
||||
{
|
||||
if(disp.update_locked())
|
||||
return -1;
|
||||
|
@ -347,6 +347,16 @@ int show_dialog(display& disp, SDL_Surface* image,
|
|||
}
|
||||
}
|
||||
|
||||
if(action_buttons != NULL) {
|
||||
for(std::vector<dialog_button>::const_iterator i = action_buttons->begin(); i != action_buttons->end(); ++i) {
|
||||
button new_button(disp,i->label);
|
||||
check_button_height += new_button.height() + button_height_padding;
|
||||
check_button_width = maximum(new_button.width(),check_button_width);
|
||||
|
||||
check_buttons.push_back(new_button);
|
||||
}
|
||||
}
|
||||
|
||||
const int left_padding = 10;
|
||||
const int right_padding = 10;
|
||||
const int image_h_padding = image != NULL ? 10 : 0;
|
||||
|
@ -470,14 +480,17 @@ int show_dialog(display& disp, SDL_Surface* image,
|
|||
|
||||
//set the position of any tick boxes. they go right below the menu, slammed against
|
||||
//the right side of the dialog
|
||||
if(options != NULL) {
|
||||
if(check_buttons.empty() == false) {
|
||||
int options_y = text_widget_y + text_widget_height + menu_.height() + button_height_padding + menu_hpadding;
|
||||
for(size_t i = 0; i != check_buttons.size(); ++i) {
|
||||
check_buttons[i].set_x(xloc + total_width - padding_width - check_buttons[i].width());
|
||||
check_buttons[i].set_y(options_y);
|
||||
|
||||
options_y += check_buttons[i].height() + button_height_padding;
|
||||
check_buttons[i].set_check((*options)[i].checked);
|
||||
|
||||
if(options != NULL && i < options->size()) {
|
||||
check_buttons[i].set_check((*options)[i].checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,9 +636,17 @@ int show_dialog(display& disp, SDL_Surface* image,
|
|||
}
|
||||
|
||||
for(unsigned int n = 0; n != check_buttons.size(); ++n) {
|
||||
check_buttons[n].process(mousex,mousey,left_button);
|
||||
const bool pressed = check_buttons[n].process(mousex,mousey,left_button);
|
||||
check_buttons[n].draw();
|
||||
(*options)[n].checked = check_buttons[n].checked();
|
||||
|
||||
if(options != NULL && n < options->size()) {
|
||||
(*options)[n].checked = check_buttons[n].checked();
|
||||
} else if(pressed) {
|
||||
const size_t options_size = options == NULL ? 0 : options->size();
|
||||
assert(action_buttons != NULL && action_buttons->size() > n - options_size);
|
||||
|
||||
(*action_buttons)[n - options_size].handler->button_pressed(menu_.selection());
|
||||
}
|
||||
}
|
||||
|
||||
if(action != NULL) {
|
||||
|
|
|
@ -58,6 +58,23 @@ public:
|
|||
enum { CONTINUE_DIALOG=-2 };
|
||||
};
|
||||
|
||||
class dialog_button_action
|
||||
{
|
||||
public:
|
||||
virtual ~dialog_button_action() {}
|
||||
|
||||
virtual void button_pressed(int menu_selection) = 0;
|
||||
};
|
||||
|
||||
struct dialog_button
|
||||
{
|
||||
dialog_button(dialog_button_action* handler, const std::string& label) : handler(handler), label(label)
|
||||
{}
|
||||
|
||||
dialog_button_action* handler;
|
||||
std::string label;
|
||||
};
|
||||
|
||||
enum { ESCAPE_DIALOG=-3 };
|
||||
|
||||
enum DIALOG_TYPE { MESSAGE, OK_ONLY, YES_NO, OK_CANCEL, CANCEL_ONLY };
|
||||
|
@ -83,7 +100,8 @@ int show_dialog(display& screen, SDL_Surface* image,
|
|||
std::string* text_widget_text=NULL,
|
||||
dialog_action* action=NULL,
|
||||
std::vector<check_item>* options=NULL, int xloc=-1, int yloc=-1,
|
||||
const std::string* dialog_style=NULL
|
||||
const std::string* dialog_style=NULL,
|
||||
std::vector<dialog_button>* buttons=NULL
|
||||
);
|
||||
|
||||
network::connection network_data_dialog(display& disp, const std::string& msg, config& cfg, network::connection connection_num=0);
|
||||
|
|
|
@ -325,24 +325,28 @@ int unit_movement_type::defense_modifier(const gamemap& map,
|
|||
|
||||
int unit_movement_type::damage_against(const attack_type& attack) const
|
||||
{
|
||||
int res = -1;
|
||||
const int resist = resistance_against(attack);
|
||||
return (attack.damage()*resist)/100;
|
||||
}
|
||||
|
||||
int unit_movement_type::resistance_against(const attack_type& attack) const
|
||||
{
|
||||
bool result_found = false;
|
||||
int res = 0;
|
||||
|
||||
const config* const resistance = cfg_.child("resistance");
|
||||
if(resistance != NULL) {
|
||||
const std::string& val = (*resistance)[attack.type()];
|
||||
if(val != "") {
|
||||
const int resist = atoi(val.c_str());
|
||||
res = (resist*attack.damage())/100;
|
||||
res = atoi(val.c_str());
|
||||
result_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(res == -1 && parent_ != NULL) {
|
||||
res = parent_->damage_against(attack);
|
||||
if(!result_found && parent_ != NULL) {
|
||||
res = parent_->resistance_against(attack);
|
||||
}
|
||||
|
||||
if(res <= 0)
|
||||
res = 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ public:
|
|||
int movement_cost(const gamemap& map, gamemap::TERRAIN terrain) const;
|
||||
int defense_modifier(const gamemap& map, gamemap::TERRAIN terrain) const;
|
||||
int damage_against(const attack_type& attack) const;
|
||||
int resistance_against(const attack_type& attack) const;
|
||||
|
||||
string_map damage_table() const;
|
||||
|
||||
|
|
19
wesnoth.dsp
19
wesnoth.dsp
|
@ -66,7 +66,6 @@ LINK32=link.exe
|
|||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
|
@ -79,7 +78,7 @@ BSC32=bscmake.exe
|
|||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_ttf.lib SDL_mixer.lib SDL_net.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
|
@ -116,6 +115,10 @@ SOURCE=.\src\widgets\button.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\cavegen.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\widgets\combo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -272,6 +275,10 @@ SOURCE=.\src\sound.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\statistics.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\team.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -332,6 +339,10 @@ SOURCE=.\src\widgets\button.hpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\cavegen.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\widgets\combo.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -492,6 +503,10 @@ SOURCE=.\src\sound.hpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\statistics.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\team.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
Loading…
Add table
Reference in a new issue