Remove battle_stats entirely from mouse_event.cpp

(finish its conversion to battle_context)

The calculation of "best" attack weapon is now based on a rating from
battle_conext: even if it has changed under some circumstances, it's
only used to choose which weapon to highlight by default anyway.
This commit is contained in:
Rusty Russell 2006-04-27 12:32:00 +00:00
parent 8ccb9a8149
commit e3ab954c17
3 changed files with 42 additions and 127 deletions

View file

@ -987,6 +987,22 @@ void battle_context::unit_stats::dump() const
printf("\n");
}
// How good is this weapon attacking? Higher is better. WML controls weighting factor.
unsigned int battle_context::rate_attacker_weapon(double attack_weight) const
{
// Weapon can kill the enemy in one blow: good
if (attacker_stats_->damage >= (int)defender_stats_->hp)
attack_weight *= 2;
// Opponent drains: bad.
if (defender_stats_->drains)
attack_weight /= 2;
attack_weight *= attacker_stats_->num_blows * attacker_stats_->damage;
attack_weight /= defender_stats_->num_blows * defender_stats_->damage;
return (unsigned int)(attack_weight * 100);
}
int battle_context::rate_defender_weapon(const unit_stats&, const unit_stats& d_stats)
{
// This is the old defend heuristic needed to maintain backward

View file

@ -162,6 +162,9 @@ public:
// This method returns the statistics of the defender.
const unit_stats& get_defender_stats() const { return *defender_stats_; }
// How good is this weapon attacking? Higher is better. WML controls weighting factor.
unsigned int rate_attacker_weapon(double attack_weight) const;
private:
// This method rates the defender weapon specified in 'd_stats', possibly taking into

View file

@ -38,53 +38,6 @@ bool command_active()
}
namespace{
//which attack is the better one to select for the player by default
//(the player can change the selected weapon if desired)
class simple_attack_rating
{
public:
simple_attack_rating() {}
simple_attack_rating(const battle_stats& stats) : stats_(stats) {}
bool operator<(const simple_attack_rating& a) const
{
//if our weapon can kill the enemy in one blow, the enemy does not
//drain back and our weapon has more blows, prefer our weapon
if(stats_.damage_defender_takes >= stats_.defender_hp &&
stats_.amount_defender_drains == 0 &&
stats_.nattacks > a.stats_.nattacks)
{
return false;
}
int this_avg_damage_dealt = stats_.chance_to_hit_defender *
stats_.damage_defender_takes * stats_.nattacks;
int this_avg_damage_taken = stats_.chance_to_hit_attacker *
stats_.damage_attacker_takes * stats_.ndefends;
int other_avg_damage_dealt = a.stats_.chance_to_hit_defender *
a.stats_.damage_defender_takes * a.stats_.nattacks;
int other_avg_damage_taken = a.stats_.chance_to_hit_attacker *
a.stats_.damage_attacker_takes * a.stats_.ndefends;
//if our weapon does less damage, it's worse
if(this_avg_damage_dealt < other_avg_damage_dealt)
return true;
//if both weapons are the same but
//ours makes the enemy retaliate for more damage, it's worse
else if(this_avg_damage_dealt == other_avg_damage_dealt &&
this_avg_damage_taken > other_avg_damage_taken)
return true;
//otherwise, ours is at least as good a default weapon
return false;
}
private:
battle_stats stats_;
};
// This preview pane is shown in the "Damage Calculations" dialog.
class battle_prediction_pane : public gui::preview_pane
{
@ -692,62 +645,6 @@ namespace{
const gamemap::location& attacker_loc_;
const gamemap::location& defender_loc_;
};
class attack_calculations_displayer : public gui::dialog_button_action
{
public:
typedef std::vector< battle_stats_strings > stats_vector;
attack_calculations_displayer(display &disp, stats_vector const &stats)
: disp_(disp), stats_(stats)
{}
RESULT button_pressed(int selection);
private:
display &disp_;
stats_vector const &stats_;
};
gui::dialog_button_action::RESULT attack_calculations_displayer::button_pressed(int selection)
{
const size_t index = size_t(selection);
if(index < stats_.size()) {
battle_stats_strings const &sts = stats_[index];
std::vector< std::string > sts_att = sts.attack_calculations,
sts_def = sts.defend_calculations,
calcs;
unsigned sts_att_sz = sts_att.size(),
sts_def_sz = sts_def.size(),
sts_sz = maximum< unsigned >(sts_att_sz, sts_def_sz);
std::stringstream str;
str << _("Attacker") << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR;
if (sts_def_sz > 0)
str << _("Defender");
calcs.push_back(str.str());
for(unsigned i = 0; i < sts_sz; ++i) {
std::stringstream str;
if (i < sts_att_sz)
str << sts_att[i];
else
str << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR << ' ';
str << COLUMN_SEPARATOR;
if (i < sts_def_sz)
str << sts_def[i];
else
str << ' ' << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR << ' ';
calcs.push_back(str.str());
}
gui::show_dialog(disp_, NULL, "", _("Damage Calculations"), gui::OK_ONLY, &calcs);
}
return NO_EFFECT;
}
} //end anonymous namespace
mouse_handler::mouse_handler(display* gui, std::vector<team>& teams, unit_map& units, gamemap& map,
@ -1266,50 +1163,49 @@ bool mouse_handler::attack_enemy(unit_map::iterator attacker, unit_map::iterator
std::vector<int> weapons;
int best_weapon_index = -1;
simple_attack_rating best_weapon_rating;
unsigned int best_weapon_rating;
attack_calculations_displayer::stats_vector stats;
std::vector<battle_context> bc_vector;
for(size_t a = 0; a != attacks.size(); ++a) {
// skip weapons with attack_weight=0
if (attacks[a].attack_weight() > 0){
weapons.push_back(a);
battle_stats_strings sts;
battle_stats st = evaluate_battle_stats(map_, teams_, attacker_loc, defender_loc,
a, units_, status_, gameinfo_, 0, &sts);
stats.push_back(sts);
battle_context bc(map_, teams_, units_, status_, gameinfo_, attacker_loc, defender_loc, attacks[a]);
bc_vector.push_back(bc);
unsigned int weapon_rating = bc.rate_attacker_weapon(attacks[a].attack_weight());
simple_attack_rating weapon_rating(st);
if (best_weapon_index < 0 || best_weapon_rating < weapon_rating) {
best_weapon_index = items.size();
best_weapon_rating = weapon_rating;
}
const battle_context::unit_stats &att(bc.get_attacker_stats()), &def(bc.get_defender_stats());
config tmp_config;
attack_type no_weapon(tmp_config, "fake_attack", "");
const attack_type &attw(*att.weapon);
const attack_type &defw(def.weapon ? *def.weapon : no_weapon);
//if there is an attack special or defend special, we output a single space for the other unit, to make sure
//that the attacks line up nicely.
std::string special_pad = (sts.attack_special.empty() && sts.defend_special.empty()) ? "" : " ";
std::string special_pad = "";
if (!attw.weapon_specials().empty() || !defw.weapon_specials().empty())
special_pad = " ";
int damage_defender_takes;
damage_defender_takes = st.damage_defender_takes;
int damage_attacker_takes;
damage_attacker_takes = st.damage_attacker_takes;
std::stringstream att;
att << IMAGE_PREFIX << sts.attack_icon << COLUMN_SEPARATOR
<< font::BOLD_TEXT << sts.attack_name << "\n" << damage_defender_takes << "-"
<< st.nattacks << " " << sts.range << " (" << st.chance_to_hit_defender << "%)\n"
<< sts.attack_special << special_pad
<< COLUMN_SEPARATOR << _("vs") << COLUMN_SEPARATOR
<< font::BOLD_TEXT << sts.defend_name << "\n" << damage_attacker_takes << "-"
<< st.ndefends << " " << sts.range << " (" << st.chance_to_hit_attacker << "%)\n"
<< sts.defend_special << special_pad << COLUMN_SEPARATOR
<< IMAGE_PREFIX << sts.defend_icon;
std::stringstream atts;
atts << IMAGE_PREFIX << attw.icon() << COLUMN_SEPARATOR
<< font::BOLD_TEXT << attw.name() << "\n" << att.damage << "-"
<< att.num_blows << " " << attw.range() << " (" << att.chance_to_hit << "%)\n"
<< attw.weapon_specials() << special_pad
<< COLUMN_SEPARATOR << _("vs") << COLUMN_SEPARATOR
<< font::BOLD_TEXT << defw.name() << "\n" << def.damage << "-"
<< def.num_blows << " " << defw.range() << " (" << def.chance_to_hit << "%)\n"
<< defw.weapon_specials() << special_pad << COLUMN_SEPARATOR
<< IMAGE_PREFIX << defw.icon();
items.push_back(att.str());
items.push_back(atts.str());
}
}