// Given this harm_weight, are we better than this other context? bool battle_context::better_attack(class battle_context& that, double harm_weight) { return better_combat( get_attacker_combatant(), get_defender_combatant(), that.get_attacker_combatant(), that.get_defender_combatant(), harm_weight ); }
/** @todo FIXME: Hand previous defender unit in here. */ int battle_context::choose_defender_weapon(const unit &attacker, const unit &defender, unsigned attacker_weapon, const unit_map& units, const map_location& attacker_loc, const map_location& defender_loc, const combatant *prev_def) { VALIDATE(attacker_weapon < attacker.attacks().size(), _("An invalid attacker weapon got selected.")); const attack_type &att = attacker.attacks()[attacker_weapon]; std::vector<unsigned int> choices; // What options does defender have? unsigned int i; for (i = 0; i < defender.attacks().size(); ++i) { const attack_type &def = defender.attacks()[i]; if (def.range() == att.range() && def.defense_weight() > 0) { choices.push_back(i); } } if (choices.empty()) return -1; if (choices.size() == 1) return choices[0]; // Multiple options: // First pass : get the best weight and the minimum simple rating for this weight. // simple rating = number of blows * damage per blows (resistance taken in account) * cth * weight // Elligible attacks for defense should have a simple rating greater or equal to this weight. double max_weight = 0.0; int min_rating = 0; for (i = 0; i < choices.size(); ++i) { const attack_type &def = defender.attacks()[choices[i]]; if (def.defense_weight() >= max_weight) { max_weight = def.defense_weight(); const battle_context_unit_stats def_stats(defender, defender_loc, choices[i], false, attacker, attacker_loc, &att, units); int rating = static_cast<int>(def_stats.num_blows * def_stats.damage * def_stats.chance_to_hit * def.defense_weight()); if (def.defense_weight() > max_weight || rating < min_rating ) { min_rating = rating; } } } // Multiple options: simulate them, save best. for (i = 0; i < choices.size(); ++i) { const attack_type &def = defender.attacks()[choices[i]]; battle_context_unit_stats *att_stats = new battle_context_unit_stats(attacker, attacker_loc, attacker_weapon, true, defender, defender_loc, &def, units); battle_context_unit_stats *def_stats = new battle_context_unit_stats(defender, defender_loc, choices[i], false, attacker, attacker_loc, &att, units); combatant *att_comb = new combatant(*att_stats); combatant *def_comb = new combatant(*def_stats, prev_def); att_comb->fight(*def_comb); int simple_rating = static_cast<int>(def_stats->num_blows * def_stats->damage * def_stats->chance_to_hit * def.defense_weight()); if (simple_rating >= min_rating && ( !attacker_combatant_ || better_combat(*def_comb, *att_comb, *defender_combatant_, *attacker_combatant_, 1.0) ) ) { delete attacker_combatant_; delete defender_combatant_; delete attacker_stats_; delete defender_stats_; attacker_combatant_ = att_comb; defender_combatant_ = def_comb; attacker_stats_ = att_stats; defender_stats_ = def_stats; } else { delete att_comb; delete def_comb; delete att_stats; delete def_stats; } } return defender_stats_->attack_num; }
int battle_context::choose_attacker_weapon(const unit &attacker, const unit &defender, const unit_map& units, const map_location& attacker_loc, const map_location& defender_loc, double harm_weight, int *defender_weapon, const combatant *prev_def) { std::vector<unsigned int> choices; // What options does attacker have? unsigned int i; for (i = 0; i < attacker.attacks().size(); ++i) { const attack_type &att = attacker.attacks()[i]; if (att.attack_weight() > 0) { choices.push_back(i); } } if (choices.empty()) return -1; if (choices.size() == 1) { *defender_weapon = choose_defender_weapon(attacker, defender, choices[0], units, attacker_loc, defender_loc, prev_def); return choices[0]; } // Multiple options: simulate them, save best. battle_context_unit_stats *best_att_stats = NULL, *best_def_stats = NULL; combatant *best_att_comb = NULL, *best_def_comb = NULL; for (i = 0; i < choices.size(); ++i) { const attack_type &att = attacker.attacks()[choices[i]]; int def_weapon = choose_defender_weapon(attacker, defender, choices[i], units, attacker_loc, defender_loc, prev_def); // If that didn't simulate, do so now. if (!attacker_combatant_) { const attack_type *def = NULL; if (def_weapon >= 0) { def = &defender.attacks()[def_weapon]; } attacker_stats_ = new battle_context_unit_stats(attacker, attacker_loc, choices[i], true, defender, defender_loc, def, units); defender_stats_ = new battle_context_unit_stats(defender, defender_loc, def_weapon, false, attacker, attacker_loc, &att, units); attacker_combatant_ = new combatant(*attacker_stats_); defender_combatant_ = new combatant(*defender_stats_, prev_def); attacker_combatant_->fight(*defender_combatant_); } if (!best_att_comb || better_combat(*attacker_combatant_, *defender_combatant_, *best_att_comb, *best_def_comb, harm_weight)) { delete best_att_comb; delete best_def_comb; delete best_att_stats; delete best_def_stats; best_att_comb = attacker_combatant_; best_def_comb = defender_combatant_; best_att_stats = attacker_stats_; best_def_stats = defender_stats_; } else { delete attacker_combatant_; delete defender_combatant_; delete attacker_stats_; delete defender_stats_; } attacker_combatant_ = NULL; defender_combatant_ = NULL; attacker_stats_ = NULL; defender_stats_ = NULL; } attacker_combatant_ = best_att_comb; defender_combatant_ = best_def_comb; attacker_stats_ = best_att_stats; defender_stats_ = best_def_stats; *defender_weapon = defender_stats_->attack_num; return attacker_stats_->attack_num; }
int battle_context::choose_attacker_weapon(const unit& attacker, const unit& defender, const unit_map& units, const map_location& attacker_loc, const map_location& defender_loc, double harm_weight, int* defender_weapon, const combatant* prev_def) { std::vector<unsigned int> choices; // What options does attacker have? unsigned int i; for(i = 0; i < attacker.attacks().size(); ++i) { const attack_type& att = attacker.attacks()[i]; if(att.attack_weight() > 0) { choices.push_back(i); } } if(choices.empty()) { return -1; } if(choices.size() == 1) { *defender_weapon = choose_defender_weapon(attacker, defender, choices[0], units, attacker_loc, defender_loc, prev_def); const_attack_ptr def_weapon = *defender_weapon >= 0 ? defender.attacks()[*defender_weapon].shared_from_this() : nullptr; attacker_stats_.reset(new battle_context_unit_stats( attacker, attacker_loc, choices[0], true, defender, defender_loc, def_weapon, units)); if(attacker_stats_->disable) { return -1; } const attack_type& att = attacker.attacks()[choices[0]]; defender_stats_.reset(new battle_context_unit_stats( defender, defender_loc, *defender_weapon, false, attacker, attacker_loc, att.shared_from_this(), units)); return choices[0]; } // Multiple options: simulate them, save best. std::unique_ptr<battle_context_unit_stats> best_att_stats(nullptr); std::unique_ptr<battle_context_unit_stats> best_def_stats(nullptr); std::unique_ptr<combatant> best_att_comb(nullptr); std::unique_ptr<combatant> best_def_comb(nullptr); for(i = 0; i < choices.size(); ++i) { const attack_type& att = attacker.attacks()[choices[i]]; int def_weapon = choose_defender_weapon(attacker, defender, choices[i], units, attacker_loc, defender_loc, prev_def); // If that didn't simulate, do so now. if(!attacker_combatant_) { const_attack_ptr def = nullptr; if(def_weapon >= 0) { def = defender.attacks()[def_weapon].shared_from_this(); } attacker_stats_.reset(new battle_context_unit_stats( attacker, attacker_loc, choices[i], true, defender, defender_loc, def, units)); if(attacker_stats_->disable) { continue; } defender_stats_.reset(new battle_context_unit_stats( defender, defender_loc, def_weapon, false, attacker, attacker_loc, att.shared_from_this(), units)); attacker_combatant_.reset(new combatant(*attacker_stats_)); defender_combatant_.reset(new combatant(*defender_stats_, prev_def)); attacker_combatant_->fight(*defender_combatant_); } else { if(attacker_stats_ != nullptr && attacker_stats_->disable) { continue; } } if(!best_att_comb || better_combat(*attacker_combatant_, *defender_combatant_, *best_att_comb, *best_def_comb, harm_weight) ) { best_att_comb = std::move(attacker_combatant_); best_def_comb = std::move(defender_combatant_); best_att_stats = std::move(attacker_stats_); best_def_stats = std::move(defender_stats_); } attacker_combatant_.reset(); defender_combatant_.reset(); attacker_stats_.reset(); defender_stats_.reset(); } attacker_combatant_ = std::move(best_att_comb); defender_combatant_ = std::move(best_def_comb); attacker_stats_ = std::move(best_att_stats); defender_stats_ = std::move(best_def_stats); // These currently mean the same thing, but assumptions like that have been broken before if(!defender_stats_ || !attacker_stats_) { return -1; } *defender_weapon = defender_stats_->attack_num; return attacker_stats_->attack_num; }