16#define GETTEXT_DOMAIN "wesnoth-lib"
52 , attacker_data_(
std::move(attacker), bc.get_attacker_combatant(), bc.get_attacker_stats())
53 , defender_data_(
std::move(defender), bc.get_defender_combatant(), bc.get_defender_stats())
59 label& title = find_widget<label>(
"title");
71 if(
mode ==
"biased") {
72 return _(
"Reduced RNG");
75 if(
mode ==
"deterministic") {
76 return _(
"Predictable RNG");
79 return _(
"Default RNG");
87 std::string description;
88 if(
mode ==
"biased") {
90 description =
_(
"Hits and misses are much more consistent. This tends to make small-scale engagements easier to plan.\n\nExample: if you strike three times with 50% accuracy, you will always hit at least once and miss at least once.");
91 }
else if(
mode ==
"deterministic") {
92 description =
_(
"Identical to Default RNG, except loading a saved game will not change the outcome of an attack.\n\nExample: you strike twice and get lucky, hitting both strikes. You then load an earlier save and make the same attack again. Both strikes will still hit.");
95 description =
_(
"Pure, unbiased randomness; the way Wesnoth is intended to be played.\n\nExample: if you strike twice with 50% accuracy, you’re most likely to hit once and miss once, but might also hit twice or miss twice.");
103 std::ostringstream ss;
108 ss << std::fixed << std::setprecision(1) << 100.0 * prob <<
'%';
117 const std::string widget_id_prefix = attacker.
stats_.
is_attacker ?
"attacker" :
"defender";
119 const auto get_prefixed_widget_id = [&widget_id_prefix](
const std::string&
id) {
120 return (
formatter() << widget_id_prefix <<
"_" <<
id).str();
124 const auto set_label_helper = [&,
this](
const std::string&
id,
const std::string&
value) {
126 label& lbl = this->find_widget<label>(get_prefixed_widget_id(
id));
130 const auto hide_label_helper = [&,
this](
const std::string&
id) {
132 label& lbl = this->find_widget<label>(get_prefixed_widget_id(
id));
134 label& lbl2 = this->find_widget<label>(get_prefixed_widget_id(
id) +
"_label");
138 std::stringstream ss;
148 set_label_helper(
"chance_unscathed", ss.str());
151 drawing& graph_widget = find_widget<drawing>(get_prefixed_widget_id(
"hp_graph"));
159 set_label_helper(
"base_damage",
_(
"No usable weapon"));
162 hide_label_helper(
"tod_modifier");
163 hide_label_helper(
"leadership_modifier");
164 hide_label_helper(
"slowed_modifier");
175 { attacker.
unit_, attacker.
unit_->get_location(), weapon },
183 auto set_dmg_effect = std::find_if(dmg_effect.
begin(), dmg_effect.
end(),
188 if(set_dmg_effect == dmg_effect.
end()) {
189 ss << weapon->damage() <<
" (" <<
markup::italic(weapon->name()) <<
")";
191 assert(set_dmg_effect->ability);
192 ss << set_dmg_effect->value <<
" (" <<
markup::italic((*set_dmg_effect->ability)[
"name"]) <<
")";
196 for(
const auto&
e : dmg_effect) {
210 for(
const auto&
e : dmg_effect) {
216 ss <<
"." << ((
e.value % 100) / 10);
218 ss << (
e.value % 10);
226 set_label_helper(
"base_damage", ss.str());
231 const auto [damage_type, resistance_modifier] = weapon->effective_damage_type();
232 if(resistance_modifier != 100) {
234 if(resistance_modifier < 100) {
235 ss <<
_(
"Defender resistance vs") <<
" ";
237 ss <<
_(
"Defender vulnerability vs") <<
" ";
240 if(resistance_modifier < 100) {
241 ss <<
_(
"Attacker resistance vs") <<
" ";
243 ss <<
_(
"Attacker vulnerability vs") <<
" ";
249 set_label_helper(
"resis_label", ss.str());
254 set_label_helper(
"resis", ss.str());
264 unit_alignments::type alignment = weapon->alignment().value_or(u.
alignment());
268 if(tod_modifier != 0) {
271 hide_label_helper(
"tod_modifier");
277 hide_label_helper(
"leadership_modifier");
282 set_label_helper(
"slowed_modifier",
"/ 2");
284 hide_label_helper(
"slowed_modifier");
288 const int base_damage = weapon->damage();
300 set_label_helper(
"total_damage", ss.str());
308 set_label_helper(
"chance_to_hit", ss.str());
318 const int hp_sep = 30;
321 const int percent_sep = 50;
324 const int bar_space =
graph_width - hp_sep - percent_sep - 4;
340 auto [hp, prob] = probability;
346 row_color = {229, 0, 0};
350 else if(hp <
static_cast<int>(attacker.
stats_.
hp)) {
353 row_color = {154, 154, 154};
355 row_color = {244, 201, 0};
361 row_color = {8, 202, 0};
366 shape[
"y"] = 2 + (
fs + 2) *
i;
367 shape[
"w"] =
"(text_width)";
368 shape[
"h"] =
"(text_height)";
369 shape[
"font_size"] = 12;
370 shape[
"color"] =
"255, 255, 255, 255";
371 shape[
"text_alignment"] =
"(text_alignment)";
378 shape[
"y"] = 2 + (
fs + 2) *
i;
379 shape[
"w"] =
"(text_width)";
380 shape[
"h"] =
"(text_height)";
381 shape[
"font_size"] = 12;
382 shape[
"color"] =
"255, 255, 255, 255";
383 shape[
"text_alignment"] =
"(text_alignment)";
387 const int bar_len = std::max(
static_cast<int>((prob * (bar_space - 4)) + 0.5), 2);
389 const rect bar_rect_1 {
397 shape[
"x"] = bar_rect_1.x;
398 shape[
"y"] = bar_rect_1.y;
399 shape[
"w"] = bar_rect_1.w;
400 shape[
"h"] = bar_rect_1.h;
416 for(
int i = 0; i < static_cast<int>(hp_dist.size()); ++
i) {
417 const double prob = hp_dist[
i];
421 temp_vec.emplace_back(
i, prob);
426 std::sort(temp_vec.begin(), temp_vec.end(), [](
const auto& pair1,
const auto& pair2) {
427 return pair1.second > pair2.second;
431 std::copy_n(temp_vec.begin(), std::min<int>(
graph_max_rows, temp_vec.size()), std::back_inserter(res));
434 std::sort(res.begin(), res.end(), [](
const auto& pair1,
const auto& pair2) {
435 return pair1.first > pair2.first;
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_alignments::type alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to the current time of day.
Computes the statistics of a battle between an attacker and a defender unit.
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
A simple canvas which can be drawn upon.
void set_variable(const std::string &key, wfl::variant &&value)
static const unsigned int graph_width
attack_predictions(battle_context &bc, unit_const_ptr attacker, unit_const_ptr defender)
static std::string rng_mode_name()
void draw_hp_graph(drawing &hp_graph, const combatant_data &attacker, const combatant_data &defender)
static std::string rng_mode_tooltip()
static const unsigned int graph_height
void set_data(const combatant_data &attacker, const combatant_data &defender)
static const unsigned int graph_max_rows
virtual void pre_show() override
Actions to be taken before showing the window.
combatant_data attacker_data_
hp_probability_vector get_hitpoint_probabilities(const std::vector< double > &hp_dist) const
combatant_data defender_data_
Abstract base class for all modal dialogs.
void append_drawing_data(const ::config &cfg)
canvas & get_drawing_canvas()
show_mode mode() const
Returns the dialog mode for this window.
static specials_context_t make(specials_combatant &&self, specials_combatant &&other, bool attacking)
const_iterator end() const
const_iterator begin() const
This class represents a single unit of a specific type.
Definitions for the interface to Wesnoth Markup Language (WML).
static std::string _(const char *str)
unit_alignments::type alignment() const
The alignment of this unit.
const map_location & get_location() const
The current map location this unit is at.
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
std::string id
Text to match against addon_info.tags()
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
const std::string unicode_multiplication_sign
const color_t good_dmg_color
const color_t weapon_color
const std::string weapon_numbers_sep
const color_t bad_dmg_color
color_t red_to_green(double val, bool for_text)
Return a color corresponding to the value val red for val=0.0 to green for val=100....
static std::string get_probability_string(const double prob)
std::vector< std::pair< int, double > > hp_probability_vector
std::string italic(Args &&... data)
Applies italic Pango markup to the input.
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
game_classification * classification
std::string signed_percent(int val)
Convert into a percentage (using the Unicode "−" and +0% convention.
std::shared_ptr< const unit > unit_const_ptr
std::shared_ptr< const attack_type > const_attack_ptr
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
unsigned int num_blows
Effective number of blows, takes swarm into account.
bool petrifies
Attack petrifies opponent when it hits.
unsigned int hp
Hitpoints of the unit at the beginning of the battle.
bool is_attacker
True if the unit is the attacker.
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
bool is_slowed
True if the unit is slowed at the beginning of the battle.
int damage
Effective damage of the weapon (all factors accounted for).
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
The basic class for representing 8-bit RGB or RGBA colour values.
std::string to_rgba_string() const
Returns the stored color as an "R,G,B,A" string.
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
double untouched
Resulting chance we were not hit by this opponent (important if it poisons)
const battle_context_unit_stats & stats_
unit_const_ptr unit_
never null
const combatant & combatant_
An abstract description of a rectangle with integer coordinates.