57 #define DBG_NG LOG_STREAM(debug, log_engine)
58 #define LOG_NG LOG_STREAM(info, log_engine)
59 #define WRN_NG LOG_STREAM(err, log_engine)
60 #define ERR_NG LOG_STREAM(err, log_engine)
63 #define LOG_CF LOG_STREAM(info, log_config)
69 const map_location& u_loc,
int u_attack_num,
bool attacking,
73 attack_num(u_attack_num),
74 is_attacker(attacking),
75 is_poisoned(u.get_state(
unit::STATE_POISONED)),
76 is_slowed(u.get_state(
unit::STATE_SLOWED)),
86 experience(u.experience()),
87 max_experience(u.max_experience()),
91 max_hp(u.max_hitpoints()),
107 LOG_CF <<
"Unit with " << u.
hitpoints() <<
" hitpoints found, set to 0 for damage calculations\n";
150 (opp_weapon ? opp_weapon->
parry() : 0);
163 int damage_multiplier = 100;
167 int leader_bonus = 0;
169 damage_multiplier += leader_bonus;
206 unsigned int opp_terrain_defense,
210 is_attacker(attacking),
238 if (!u_type || !opp_type) {
278 (opp_weapon ? opp_weapon->
parry() : 0);
279 cth = std::min(100, cth);
280 cth = std::max(0, cth);
288 int damage_multiplier = 100;
322 int attacker_weapon,
int defender_weapon,
double aggression,
324 attacker_stats_(nullptr), defender_stats_(nullptr), attacker_combatant_(nullptr),
325 defender_combatant_(nullptr)
327 const unit &attacker = attacker_ptr ? *attacker_ptr : *units.
find(attacker_loc);
328 const unit &defender = *units.
find(defender_loc);
329 const double harm_weight = 1.0 - aggression;
331 if (attacker_weapon == -1 && attacker.
attacks().size() == 1 && attacker.
attacks()[0].attack_weight() > 0 )
334 if (attacker_weapon == -1) {
336 attacker_loc, defender_loc,
337 harm_weight, &defender_weapon, prev_def);
338 }
else if (defender_weapon == -1) {
340 units, attacker_loc, defender_loc, prev_def);
347 if (attacker_weapon >= 0) {
348 VALIDATE(attacker_weapon < static_cast<int>(attacker.
attacks().size()),
349 _(
"An invalid attacker weapon got selected."));
350 adef = &attacker.
attacks()[attacker_weapon];
352 if (defender_weapon >= 0) {
353 VALIDATE(defender_weapon < static_cast<int>(defender.
attacks().size()),
354 _(
"An invalid defender weapon got selected."));
355 ddef = &defender.
attacks()[defender_weapon];
359 true, defender, defender_loc, ddef, units);
361 attacker, attacker_loc, adef, units);
373 attacker_combatant_(nullptr),
374 defender_combatant_(nullptr)
379 attacker_stats_(nullptr), defender_stats_(nullptr), attacker_combatant_(nullptr),
380 defender_combatant_(nullptr)
395 if (&other !=
this) {
475 double harm_weight,
int *defender_weapon,
const combatant *prev_def)
477 std::vector<unsigned int> choices;
481 for (i = 0; i < attacker.
attacks().size(); ++
i) {
484 choices.push_back(i);
489 if (choices.size() == 1) {
491 attacker_loc, defender_loc, prev_def);
492 const attack_type *def_weapon = *defender_weapon >= 0 ? &defender.
attacks()[*defender_weapon] :
nullptr;
494 true, defender, defender_loc, def_weapon, units);
502 attacker, attacker_loc, &att, units);
508 combatant *best_att_comb =
nullptr, *best_def_comb =
nullptr;
510 for (i = 0; i < choices.size(); ++
i) {
513 attacker_loc, defender_loc, prev_def);
517 if (def_weapon >= 0) {
518 def = &defender.
attacks()[def_weapon];
521 true, defender, defender_loc, def, units);
528 attacker, attacker_loc, &att, units);
534 *best_att_comb, *best_def_comb, harm_weight)) {
535 delete best_att_comb;
536 delete best_def_comb;
537 delete best_att_stats;
538 delete best_def_stats;
575 _(
"An invalid attacker weapon got selected."));
577 std::vector<unsigned int> choices;
581 for (i = 0; i < defender.
attacks().size(); ++
i) {
584 choices.push_back(i);
589 if (choices.size() == 1) {
591 choices[0],
false, attacker, attacker_loc, &att, units);
592 return (def_stats.
disable) ? -1 : choices[0];
602 double max_weight = 0.0;
604 for (i = 0; i < choices.size(); ++
i) {
608 choices[i],
false, attacker, attacker_loc, &att, units);
609 if (def_stats.
disable)
continue;
621 for (i = 0; i < choices.size(); ++
i) {
624 true, defender, defender_loc, &def, units);
626 attacker, attacker_loc, &att, units);
634 att_comb->
fight(*def_comb);
636 int simple_rating =
static_cast<int>(def_stats->
num_blows *
639 if (simple_rating >= min_rating &&
663 void refresh_weapon_index(
int& weap_index,
std::string const& weap_id, std::vector<attack_type>
const& attacks)
665 if(attacks.empty()) {
670 if(weap_index >= 0 && weap_index < static_cast<int>(attacks.size()) && attacks[weap_index].
id() == weap_id) {
674 if(!weap_id.empty()) {
676 for(
int i=0; i<static_cast<int>(attacks.size()); ++
i) {
677 if(attacks[
i].
id() == weap_id) {
694 int attack_with,
int defend_with,
bool update_display =
true);
700 class attack_end_exception {};
730 void check_replay_attack_result(
bool,
int,
int,
config, unit_info&);
732 void unit_killed(unit_info &, unit_info &,
740 int abs_n_attack_, abs_n_defend_;
742 bool update_att_fog_, update_def_fog_, update_minimap_;
746 std::ostringstream errbuf_;
748 bool update_display_;
766 if (!i.
valid())
return;
767 id_ = i->underlying_id();
770 unit &attack::unit_info::get_unit()
773 assert(i.
valid() && i->underlying_id() ==
id_);
780 return i.
valid() && i->underlying_id() ==
id_;
786 s << get_unit().type_id() <<
" (" <<
loc_.
x + 1 <<
',' <<
loc_.
y + 1 <<
')';
792 int attack_with,
int defend_with,
bool update_display) :
798 update_att_fog_(false),
799 update_def_fog_(false),
800 update_minimap_(false),
802 d_(defender, defend_with, *
resources::units),
805 update_display_(update_display),
817 LOG_NG <<
"firing " << n <<
" event\n";
822 if(a_stats_->weapon !=
nullptr &&
a_.valid()) {
823 a_stats_->weapon->write(a_weapon_cfg);
825 if(d_stats_->weapon !=
nullptr && d_.valid()) {
826 d_stats_->weapon->write(d_weapon_cfg);
828 if(a_weapon_cfg[
"name"].empty()) {
829 a_weapon_cfg[
"name"] =
"none";
831 if(d_weapon_cfg[
"name"].empty()) {
832 d_weapon_cfg[
"name"] =
"none";
834 if(n ==
"attack_end") {
839 const int defender_side = d_.get_unit().side();
846 if(!
a_.valid() || !d_.valid() || !(*resources::teams)[
a_.get_unit().side() - 1].is_enemy(d_.get_unit().side())) {
848 if (update_display_){
853 throw attack_end_exception();
857 void attack::refresh_bc()
861 refresh_weapon_index(
a_.weapon_,
a_.weap_id_,
a_.get_unit().attacks());
864 refresh_weapon_index(d_.weapon_, d_.weap_id_, d_.get_unit().attacks());
866 if(!
a_.valid() || !d_.valid()) {
869 a_.valid() &&
a_.weapon_ >= 0
870 ? &
a_.get_unit().attacks()[
a_.weapon_] :
nullptr;
873 d_.valid() && d_.weapon_ >= 0
874 ? &d_.get_unit().attacks()[d_.weapon_] :
nullptr;
880 a_stats_ = &bc_->get_attacker_stats();
881 d_stats_ = &bc_->get_defender_stats();
882 a_.cth_ = a_stats_->chance_to_hit;
883 d_.cth_ = d_stats_->chance_to_hit;
884 a_.damage_ = a_stats_->damage;
885 d_.damage_ = d_stats_->damage;
891 &attacker = *(attacker_turn ? &
a_ : &d_),
892 &defender = *(attacker_turn ? &d_ : &
a_);
894 *&attacker_stats = *(attacker_turn ? &a_stats_ : &d_stats_),
895 *&defender_stats = *(attacker_turn ? &d_stats_ : &a_stats_);
896 int &abs_n = *(attacker_turn ? &abs_n_attack_ : &abs_n_defend_);
897 bool &update_fog = *(attacker_turn ? &update_def_fog_ : &update_att_fog_);
900 bool hits = (ran_num < attacker.cth_);
904 damage = attacker.damage_;
910 const config local_results =
config_of(
"chance", attacker.cth_)(
"hits", hits)(
"damage", damage);
915 check_replay_attack_result(hits, ran_num, damage, replay_results, attacker);
919 int damage_done = std::min<int>(defender.get_unit().hitpoints(), attacker.damage_);
921 double expected_damage = damage_done*attacker.cth_*0.01;
928 int drains_damage = 0;
929 if (hits && attacker_stats->
drains) {
932 drains_damage = std::min<int>(drains_damage, attacker.get_unit().max_hitpoints() - attacker.get_unit().hitpoints());
934 drains_damage = std::max<int>(drains_damage, 1 - attacker.get_unit().hitpoints());
939 std::ostringstream float_text;
940 std::vector<std::string> extra_hit_sounds;
943 const unit &defender_unit = defender.get_unit();
946 _(
"female^poisoned") : _(
"poisoned")) <<
'\n';
953 _(
"female^slowed") : _(
"slowed")) <<
'\n';
960 _(
"female^petrified") : _(
"petrified")) <<
'\n';
967 attacker.loc_, defender.loc_, damage,
968 *attacker_stats->
weapon, defender_stats->weapon,
969 abs_n, float_text.str(), drains_damage,
"", &extra_hit_sounds);
972 bool dies = defender.get_unit().take_hit(damage);
973 LOG_NG <<
"defender took " << damage << (dies ?
" and died\n" :
"\n");
985 replay_results.
clear();
990 bool results_dies = replay_results[
"dies"].to_bool();
992 errbuf_ <<
"SYNC: In attack " << a_.dump() <<
" vs " << d_.dump()
993 <<
": the data source says the "
994 << (attacker_turn ?
"defender" :
"attacker") <<
' '
995 << (results_dies ?
"perished" :
"survived")
996 <<
" while in-game calculations show it "
997 << (dies ?
"perished" :
"survived")
998 <<
" (over-riding game calculations with data source results)\n";
1001 if (results_dies) defender.get_unit().set_hitpoints(0);
1008 fire_event(attacker_turn ?
"attacker_hits" :
"defender_hits");
1009 }
catch (attack_end_exception) {
1017 fire_event(attacker_turn ?
"attacker_misses" :
"defender_misses");
1018 }
catch (attack_end_exception) {
1025 bool attacker_dies =
false;
1026 if (drains_damage > 0) {
1027 attacker.get_unit().heal(drains_damage);
1028 }
else if(drains_damage < 0) {
1029 attacker_dies = attacker.get_unit().take_hit(-drains_damage);
1033 unit_killed(attacker, defender, attacker_stats, defender_stats,
false);
1036 if (attacker_dies) {
1037 unit_killed(defender, attacker, defender_stats, attacker_stats,
true);
1038 *(attacker_turn ? &update_att_fog_ : &update_def_fog_) =
true;
1042 update_minimap_ =
true;
1048 unit &defender_unit = defender.get_unit();
1051 LOG_NG <<
"defender poisoned\n";
1057 defender.damage_ = defender_stats->slow_damage;
1058 LOG_NG <<
"defender slowed\n";
1065 attacker.n_attacks_ = 0;
1066 defender.n_attacks_ = -1;
1074 update_minimap_ =
true;
1078 --attacker.n_attacks_;
1082 void attack::unit_killed(unit_info& attacker, unit_info& defender,
1093 std::string undead_variation = defender.get_unit().undead_variation();
1099 config a_weapon_cfg = attacker_stats->
weapon && attacker.valid() ?
1101 config d_weapon_cfg = defender_stats->
weapon && defender.valid() ?
1103 if (a_weapon_cfg[
"name"].empty())
1104 a_weapon_cfg[
"name"] =
"none";
1105 if (d_weapon_cfg[
"name"].empty())
1106 d_weapon_cfg[
"name"] =
"none";
1113 if (!defender.valid() || defender.get_unit().hitpoints() > 0) {
1118 if (!attacker.valid()) {
1120 nullptr, defender_stats->
weapon);
1124 attacker.loc_, &attacker.get_unit());
1130 if (!defender.valid() || defender.get_unit().hitpoints() > 0) {
1135 units_.erase(defender.loc_);
1137 if (attacker.valid() && attacker_stats->
plagues && !drain_killed)
1145 LOG_NG <<
"found unit type:" << reanimator->
id() <<
'\n';
1146 unit newunit(*reanimator, attacker.get_unit().side(),
1149 newunit.set_movement(0,
true);
1151 if (undead_variation !=
"null")
1155 variation[
"apply_to"] =
"variation";
1156 variation[
"name"] = undead_variation;
1157 newunit.add_modification(
"variation",mod);
1160 units_.add(death_loc, newunit);
1166 if (update_display_) {
1173 LOG_NG <<
"unit not reanimated\n";
1177 void attack::perform()
1182 if(!a_.valid() || !d_.valid()) {
1187 if (a_.weapon_ < 0) {
1188 a_.get_unit().set_attacks(a_.get_unit().attacks_left()-1);
1189 a_.get_unit().set_movement(-1,
true);
1193 a_.get_unit().set_facing(a_.loc_.get_relative_dir(d_.loc_));
1194 d_.get_unit().set_facing(d_.loc_.get_relative_dir(a_.loc_));
1196 a_.get_unit().set_attacks(a_.get_unit().attacks_left()-1);
1197 VALIDATE(a_.weapon_ < static_cast<int>(a_.get_unit().attacks().size()),
1198 _(
"An invalid attacker weapon got selected."));
1199 a_.get_unit().set_movement(a_.get_unit().movement_left() -
1200 a_.get_unit().attacks()[a_.weapon_].movement_used(),
true);
1202 a_.get_unit().set_resting(
false);
1203 d_.get_unit().set_resting(
false);
1209 a_stats_ = &bc_->get_attacker_stats();
1210 d_stats_ = &bc_->get_defender_stats();
1211 if(a_stats_->weapon) {
1212 a_.weap_id_ = a_stats_->weapon->id();
1214 if(d_stats_->weapon) {
1215 d_.weap_id_ = d_stats_->weapon->id();
1220 }
catch (attack_end_exception) {
1225 DBG_NG <<
"getting attack statistics\n";
1228 a_.orig_attacks_ = a_stats_->num_blows;
1229 d_.orig_attacks_ = d_stats_->num_blows;
1230 a_.n_attacks_ = a_.orig_attacks_;
1231 d_.n_attacks_ = d_.orig_attacks_;
1232 a_.xp_ = d_.get_unit().level();
1233 d_.xp_ = a_.get_unit().level();
1235 bool defender_strikes_first = (d_stats_->firststrike && !a_stats_->firststrike);
1236 unsigned int rounds = std::max<unsigned int>(a_stats_->rounds, d_stats_->rounds) - 1;
1237 const int defender_side = d_.get_unit().side();
1239 LOG_NG <<
"Fight: (" << a_.loc_ <<
") vs (" << d_.loc_ <<
") ATT: " <<
1240 a_stats_->weapon->name() <<
" " << a_stats_->damage <<
"-" <<
1241 a_stats_->num_blows <<
"(" << a_stats_->chance_to_hit <<
"%) vs DEF: " <<
1242 (d_stats_->weapon ? d_stats_->weapon->name() :
"none") <<
" " <<
1243 d_stats_->damage <<
"-" << d_stats_->num_blows <<
1244 "(" << d_stats_->chance_to_hit <<
"%)" <<
1245 (defender_strikes_first ?
" defender first-strike" :
"") <<
"\n";
1252 DBG_NG <<
"start of attack loop...\n";
1255 if (a_.n_attacks_ > 0 && !defender_strikes_first) {
1256 if (!perform_hit(
true, attack_stats)) {
1257 DBG_NG <<
"broke from attack loop on attacker turn\n";
1263 defender_strikes_first =
false;
1266 if (d_.n_attacks_ > 0) {
1267 if (!perform_hit(
false, attack_stats)) {
1268 DBG_NG <<
"broke from attack loop on defender turn\n";
1275 if(rounds > 0 && d_.n_attacks_ == 0 && a_.n_attacks_ == 0) {
1276 a_.n_attacks_ = a_.orig_attacks_;
1277 d_.n_attacks_ = d_.orig_attacks_;
1279 defender_strikes_first = (d_stats_->firststrike && ! a_stats_->firststrike);
1282 if (a_.n_attacks_ <= 0 && d_.n_attacks_ <= 0) {
1289 if ( update_def_fog_ )
1295 if (update_minimap_ && update_display_) {
1300 unit &u = a_.get_unit();
1306 unit &u = d_.get_unit();
1312 d_stats_->weapon,d_.loc_,d_.valid()?&d_.get_unit():
nullptr);
1314 if (update_display_){
1326 void attack::check_replay_attack_result(
bool hits,
int ran_num,
int damage,
1327 config replay_results, unit_info& attacker)
1329 int results_chance = replay_results[
"chance"];
1330 bool results_hits = replay_results[
"hits"].to_bool();
1331 int results_damage = replay_results[
"damage"];
1347 if (results_chance != attacker.cth_)
1349 errbuf_ <<
"SYNC: In attack " << a_.dump() <<
" vs " << d_.dump()
1350 <<
": chance to hit is inconsistent. Data source: "
1351 << results_chance <<
"; Calculation: " << attacker.cth_
1352 <<
" (over-riding game calculations with data source results)\n";
1353 attacker.cth_ = results_chance;
1357 if (results_hits != hits)
1359 errbuf_ <<
"SYNC: In attack " << a_.dump() <<
" vs " << d_.dump()
1360 <<
": the data source says the hit was "
1361 << (results_hits ?
"successful" :
"unsuccessful")
1362 <<
", while in-game calculations say the hit was "
1363 << (hits ?
"successful" :
"unsuccessful")
1364 <<
" random number: " << ran_num <<
" = "
1365 << (ran_num % 100) <<
"/" << results_chance
1366 <<
" (over-riding game calculations with data source results)\n";
1367 hits = results_hits;
1371 if (results_damage != damage)
1373 errbuf_ <<
"SYNC: In attack " << a_.dump() <<
" vs " << d_.dump()
1374 <<
": the data source says the hit did " << results_damage
1375 <<
" damage, while in-game calculations show the hit doing "
1377 <<
" damage (over-riding game calculations with data source results)\n";
1378 damage = results_damage;
1385 int attack_with,
int defend_with,
bool update_display)
1387 attack dummy(attacker, defender, attack_with, defend_with, update_display);
1398 :
loc_ (loc), nb_options_(total_opt), side_num_(side_num), ai_advancement_(ai_advancement), force_dialog_(force_dialog)
1402 virtual ~unit_advancement_choice()
1410 team t = (*resources::teams)[side_num_ - 1];
1424 res = rand() % nb_options_;
1428 if(ai_advancement_ !=
nullptr)
1431 const std::vector<std::string>&
options = u->advances_to();
1432 const std::vector<std::string>& allowed = ai_advancement_->get_advancements(u);
1434 for(std::vector<std::string>::const_iterator
a = options.begin();
a != options.end(); ++
a) {
1435 if (
std::find(allowed.begin(), allowed.end(), *
a) != allowed.end()){
1436 res =
a - options.begin();
1450 LOG_NG <<
"unit at position " <<
loc_ <<
"choose advancement number " << res <<
"\n";
1452 retv[
"value"] =
res;
1464 return "an advancement choice";
1482 for(
int advacment_number = 0; advacment_number < 20; advacment_number++)
1492 LOG_NG <<
"Firing pre advance event at " << params.
loc_ <<
".\n";
1498 LOG_NG <<
"pre advance event aborted advancing.\n";
1509 DBG_NG <<
"animate_unit_advancement result = " << result << std::endl;
1512 if (u.
valid() && u->experience() > 80)
1514 WRN_NG <<
"Unit has too many (" << u->experience() <<
") XP left; cascade leveling goes on still." << std::endl;
1517 ERR_NG <<
"unit at " << params.
loc_ <<
"tried to advance more than 20 times. Advancing was aborted" << std::endl;
1525 int attack_with,
int defend_with,
bool update_display,
1528 attack_unit(attacker, defender, attack_with, defend_with, update_display);
1546 " to: " + advance_to);
1549 new_unit->set_experience(new_unit->experience() - new_unit->max_experience());
1550 new_unit->advance_to(*new_type);
1551 new_unit->heal_all();
1555 new_unit->set_user_end_turn(
false);
1556 new_unit->set_hidden(
false);
1567 amla_unit->set_experience(amla_unit->experience() - amla_unit->max_experience());
1568 amla_unit->add_modification(
"advancement", mod_option);
1586 LOG_NG <<
"Firing advance event at " << loc <<
".\n";
1589 if (!u.
valid() || u->experience() < u->max_experience() ||
1590 u->type_id() != original_type)
1592 LOG_NG <<
"WML has invalidated the advancing unit. Aborting.\n";
1596 loc = u->get_location();
1605 bool use_amla = mod_option !=
nullptr;
1612 LOG_CF <<
"Added '" << new_unit->type_id() <<
"' to the encountered units.\n";
1623 LOG_NG <<
"Firing post_advance event at " << loc <<
".\n";
1639 if(un == units.
end()) {
1644 *bonus = abil.
highest(
"value").first;
1646 return abil.
highest(
"value").second;
1660 switch(alignment.v) {
1661 case unit_type::ALIGNMENT::LAWFUL:
1662 bonus = lawful_bonus;
1664 case unit_type::ALIGNMENT::NEUTRAL:
1667 case unit_type::ALIGNMENT::CHAOTIC:
1668 bonus = -lawful_bonus;
1670 case unit_type::ALIGNMENT::LIMINAL:
1671 bonus = -abs(lawful_bonus);
1678 bonus = std::max<int>(bonus, 0);
1689 if(defender == units.
end())
return false;
1694 for(i = 0; i != 6; ++
i) {
1695 if(adj[i] == attacker_loc)
1698 if(i >= 6)
return false;
1701 units.
find(adj[(i+3)%6]);
1702 if(opp == units.
end())
return false;
1703 if (opp->incapacitated())
return false;
1704 if (
size_t(defender->side() - 1) >= teams.size() || size_t(opp->side() - 1) >= teams.size())
1706 if (teams[defender->side() - 1].is_enemy(opp->side()))
void advance_unit(map_location loc, const std::string &advance_to, const bool &fire_event, const config *mod_option)
Function which will advance the unit at loc to 'advance_to'.
play_controller * controller
virtual std::string description() const
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
unsigned int calc_blows(unsigned new_hp) const
Calculates the number of blows we would have if we had new_hp.
::tod_manager * tod_manager
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
const ai::unit_advancements_aspect * ai_advancements_
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
int max_hitpoints() const
bool get_state(const std::string &state) const
std::string plague_type
The plague type used by the attack, if any.
static lg::log_domain log_config("config")
void set_specials_context(const map_location &unit_loc, const map_location &other_loc, bool attacking, const attack_type *other_attack) const
Sets the context under which specials will be checked for being active.
bool clear_unit(const map_location &view_loc, team &view_team, size_t viewer_id, int sight_range, bool slowed, const movetype::terrain_costs &costs, const map_location &real_loc, const std::set< map_location > *known_units=nullptr, size_t *enemy_count=nullptr, size_t *friend_count=nullptr, move_unit_spectator *spectator=nullptr, bool instant=true)
Clears shroud (and fog) around the provided location for view_team based on sight_range, costs, and slowed.
unsigned int hp
Hitpoints of the unit at the beginning of the battle.
Various functions implementing vision (through fog of war and shroud).
void unit_attack(display *disp, game_board &board, const map_location &a, const map_location &b, int damage, const attack_type &attack, const attack_type *secondary_attack, int swing, std::string hit_text, int drain_amount, std::string att_text, const std::vector< std::string > *extra_hit_sounds)
Make the unit on tile 'a' attack the unit on tile 'b'.
double attack_weight() const
int 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)
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
Various functions that implement attacks and attack calculations.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
static bool better_combat(const combatant &us_a, const combatant &them_a, const combatant &us_b, const combatant &them_b, double harm_weight)
bool musthave_status(const std::string &status) const
rng * generator
This generator is automatically synced during synced context.
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
void advance_unit_at(const advance_unit_params ¶ms)
bool will_certainly_advance(const unit_map::iterator &u)
Encapsulates the logic for deciding whether an iterator u points to a unit that can advance...
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
bool actor_sighted(const unit &target, const std::vector< int > *cache)
Fires sighted events for the sides that can see target.
const std::string & undead_variation() const
Info on the type of unit that the unit reanimates as.
int lawful_bonus
The % bonus lawful units receive.
unit_ptr get_advanced_unit(const unit &u, const std::string &advance_to)
Returns the advanced version of a unit (with traits and items retained).
unit_type_data unit_types
bool fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
bool is_slowed
True if the unit is slowed at the beginning of the battle.
static CVideo & get_singleton()
battle_context_unit_stats * attacker_stats_
Statistics of the units.
const attack_type * weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
std::pair< int, map_location > highest(const std::string &key, int def=0) const
battle_context(const unit_map &units, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon=-1, int defender_weapon=-1, double aggression=0.0, const combatant *prev_def=nullptr, const unit *attacker_ptr=nullptr)
If no attacker_weapon is given, we select the best one, based on harm_weight (1.0 means 1 hp lost cou...
bool slows
Attack slows opponent when it hits.
void defend_result(hit_result res, int damage, int drain)
virtual void draw()
Draws invalidated items.
void set_state(const std::string &state, bool value)
int drain_constant
Base HP drained regardless of damage dealt.
const map_location & loc_
int advance_unit_dialog(const map_location &loc)
Lets the user to select a unit advancement.
void redraw_minimap()
Schedule the minimap to be redrawn.
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
virtual config random_choice(int side) const =0
int defense_modifier(const t_translation::t_terrain &terrain) const
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
bool get_special_bool(const std::string &special, bool simple_check=false) const
Returns whether or not *this has a special with a tag or id equal to special.
const unit_type & type() const
The type of the unit (accounting for gender and variation).
GLdouble GLdouble GLdouble b
bool poisons
Attack poisons opponent when it hits.
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
const combatant & get_defender_combatant(const combatant *prev_def=nullptr)
static std::vector< team > *& teams
bool backstab_pos
True if the attacker is in position to backstab the defender (this is used to determine whether to ap...
This class stores all the data for a single 'side' (in game nomenclature).
static UNUSEDNOWARN std::string _(const char *str)
int damage
Effective damage of the weapon (all factors accounted for).
int current_side() const
Returns the number of the side whose turn it is.
std::vector< team > * teams
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
const std::string & undead_variation() const
combatant * defender_combatant_
unit_type::ALIGNMENT alignment() const
bool animate_unit_advancement(const map_location &loc, size_t choice, const bool &fire_event, const bool animate)
Actually levels a unit up.
unsigned int rounds
Berserk special can force us to fight more than one round.
unsigned int swarm_min
Minimum number of blows with swarm (equal to num_blows if swarm isn't used).
size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
unit_ptr get_amla_unit(const unit &u, const config &mod_option)
Returns the AMLA-advanced version of a unit (with traits and items retained).
Interface for querying local choices.
GLboolean GLboolean GLboolean GLboolean a
bool plagues
Attack turns opponent into a zombie when fatal.
bool better_attack(class battle_context &that, double harm_weight)
Given this harm_weight, is this attack better than that?
Encapsulates the map of the game.
void recalculate_fog(int side)
Function that recalculates the fog of war.
Computes the statistics of a battle between an attacker and a defender unit.
config & add_child(const std::string &key)
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
unit_race::GENDER gender() const
bool is_local_human() const
checkup * checkup_instance
int attack_num
Index into unit->attacks() or -1 for none.
Structure describing the statistics of a unit involved in the battle.
unit_animation_component & anim_comp() const
int damage_from(const attack_type &attack, bool attacker, const map_location &loc) const
static const map_location & null_location()
std::pair< unit_iterator, bool > replace(const map_location &l, const unit &u)
Works like unit_map::add; but l is emptied first, if needed.
Error used for any general game error, e.g.
int 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)
game_events::manager * game_events
int generic_combat_modifier(int lawful_bonus, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to a given lawful_bonus.
virtual config query_user(int side) const =0
const std::string & type() const
const std::vector< attack_type > & attacks() const
void unit_draw_weapon(const map_location &loc, unit &attacker, const attack_type *attack, const attack_type *secondary_attack, const map_location &defender_loc, unit *defender)
Play a pre-fight animation First unit is the attacker, second unit the defender.
advances the unit at loc if it has enough experience, maximum 20 times.
Encapsulates the map of the game.
battle_context_unit_stats(const unit &u, const map_location &u_loc, int u_attack_num, bool attacking, const unit &opp, const map_location &opp_loc, const attack_type *opp_weapon, const unit_map &units)
void unit_die(const map_location &loc, unit &loser, const attack_type *attack, const attack_type *secondary_attack, const map_location &winner_loc, unit *winner)
Show a unit fading out.
static void process_error(const std::string &msg)
void advance_unit(const unit &u)
battle_context & operator=(const battle_context &other)
int round_damage(int base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage ...
bool backstab_check(const map_location &attacker_loc, const map_location &defender_loc, const unit_map &units, const std::vector< team > &teams)
Function to check if an attack will satisfy the requirements for backstab.
bool swarm
Attack has swarm special.
int slow_damage
Effective damage if unit becomes slowed (== damage, if already slowed)
combatant * attacker_combatant_
Outcome of simulated fight.
const std::string & range() const
Define the game's event mechanism.
bool disable
Attack has disable special.
void modified_attacks(bool is_backstab, unsigned &min_attacks, unsigned &max_attacks) const
Calculates the number of attacks this weapon has, considering specials.
bool firststrike
Attack has firststrike special.
int number_of_possible_advances(const unit &u)
Determines the total number of available advancements (of any kind) for a given unit.
std::set< std::string > & encountered_units()
bool fire_event(const tevent event, std::vector< std::pair< twidget *, tevent > > &event_chain, twidget *dispatcher, twidget *widget, F functor)
Helper function for fire_event.
unit_ability_list get_specials(const std::string &special) const
Returns the currently active specials as an ability list, given the current context (see set_specials...
boost::shared_ptr< std::vector< unit_const_ptr > > units_
game_events::t_pump & pump()
int drain_percent
Percentage of damage recovered as health.
int experience_needed(bool with_acceleration=true) const
bool fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
const time_of_day get_illuminated_time_of_day(const unit_map &units, const gamemap &map, const map_location &loc, int for_turn=0) const
Returns time of day object for the passed turn at a location.
void unit_sheath_weapon(const map_location &primary_loc, unit *primary_unit, const attack_type *primary_attack, const attack_type *secondary_attack, const map_location &secondary_loc, unit *secondary_unit)
Play a post-fight animation Both unit can be set to null, only valid units will play their animation...
const std::string & base_id() const
The id of the original type from which this (variation) descended.
bool find(E event, F functor)
Tests whether an event handler is available.
void attack_expected_damage(double attacker_inflict, double defender_inflict)
void attack_unit(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display)
Performs an attack.
Standard logging facilities (interface).
bool is_network_ai() const
void attack_result(hit_result res, int damage, int drain)
Container associating units to locations.
void set_attacks(int left)
double defense_weight() const
Class to encapsulate fog/shroud clearing and the resultant sighted events.
unsigned int num_blows
Effective number of blows, takes swarm into account.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
unsigned int max_hp
Maximum hitpoints of the unit.
double average_hp(unsigned int healing=0) const
What's the average hp (weighted average of hp_dist).
boost::shared_ptr< wb::manager > whiteboard
bool is_attacker
True if the unit is the attacker.
void set_standing(bool with_bars=true)
Sets the animation state to standing.
unsigned int max_experience
int get_composite_value() const
unit_iterator find(size_t id)
virtual bool is_networked_mp() const
virtual bool local_checkup(const config &expected_data, config &real_data)=0
Compares data to the results calculated during the original game.
bool petrifies
Attack petrifies opponent when it hits.
static lg::log_domain log_engine("engine")
A config object defines a single node in a WML file, with access to child nodes.
map_location under_leadership(const unit_map &units, const map_location &loc, int *bonus)
function which tests if the unit at loc is currently affected by leadership.
void set_experience(int xp)
std::vector< int > get_sides_not_seeing(const unit &target)
Returns the sides that cannot currently see target.
bool drains
Attack drains opponent when it hits.
GLsizei const GLcharARB ** string
Display units performing various actions: moving, attacking, and dying.
int resistance_against(const std::string &damage_name, bool attacker) const
Gets resistance while considering custom WML abilities.
void attack_unit_and_advance(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display, const ai::unit_advancements_aspect &ai_advancement)
Performs an attack, and advanced the units afterwards.
const std::string & id() const
The id for this unit_type.
double poisoned
Resulting chance we are poisoned.
battle_context_unit_stats * defender_stats_
unsigned int swarm_max
Maximum number of blows with swarm (equal to num_blows if swarm isn't used).
static game_display * get_singleton()
const std::string valid
Little parts of regex templates used to parse Wml annoations.
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to the current time of day...