mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-17 01:00:13 +00:00
Have [filter_attack/weapon]type= pick the type which does more damage (#8936)
resolve [filter_attack/weapon]type= can check both type when it wait only effective type. * add 'base_type' filter for detect original type of attack reagrdless of [damage_type] modifications if for some reason the original type must be filtered instead of effective type, this attribute is here for that. * add effective_type in formulas
This commit is contained in:
parent
2c0a1cdaa7
commit
0dce4e4731
|
@ -6,6 +6,7 @@
|
|||
{SIMPLE_KEY alignment alignment}
|
||||
{SIMPLE_KEY name string_list}
|
||||
{SIMPLE_KEY type string_list}
|
||||
{SIMPLE_KEY base_type string_list}
|
||||
{SIMPLE_KEY special string_list}
|
||||
{SIMPLE_KEY special_active string_list}
|
||||
{SIMPLE_KEY special_id string_list}
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
# wmllint: no translatables
|
||||
|
||||
#####
|
||||
# API(s) being tested: [event][filter_attack]type=
|
||||
##
|
||||
# Actions:
|
||||
# Give Alice an ability that adds a damage special with addition of arcnae type to all of his weapons.
|
||||
# Define events that use filter_attack matching Alice's arcane type.
|
||||
# Have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# An event triggers when Alice attacks during side 1's turn because type=arcane detected.
|
||||
#####
|
||||
{GENERIC_UNIT_TEST event_test_filter_attack_type (
|
||||
#define FILTER_TYPE VALUE
|
||||
[event]
|
||||
name=start
|
||||
[object]
|
||||
|
@ -29,6 +18,19 @@
|
|||
id=alice
|
||||
[/filter]
|
||||
[/object]
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=resistance
|
||||
replace=yes
|
||||
[resistance]
|
||||
arcane={VALUE}
|
||||
[/resistance]
|
||||
[/effect]
|
||||
[filter]
|
||||
id=bob
|
||||
[/filter]
|
||||
[/object]
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
|
@ -84,8 +86,171 @@
|
|||
{ASSERT ({VARIABLE_CONDITIONAL triggers equals 0})}
|
||||
{VARIABLE_OP triggers add 1}
|
||||
[/event]
|
||||
#enddef
|
||||
|
||||
#####
|
||||
# API(s) being tested: [event][filter_attack]type=
|
||||
##
|
||||
# Actions:
|
||||
# Give Alice an ability that adds a damage special with addition of arcnae type to all of his weapons.
|
||||
# Give Bob resistance to -100% to arcane
|
||||
# Define events that use filter_attack matching Alice's arcane type.
|
||||
# Have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# The event triggers when Alice attacks, because the result is calculated using arcane as the damage type
|
||||
#####
|
||||
{GENERIC_UNIT_TEST event_test_filter_attack_type (
|
||||
{FILTER_TYPE 200}
|
||||
|
||||
[event]
|
||||
name=turn 2
|
||||
{RETURN ({VARIABLE_CONDITIONAL triggers equals 1})}
|
||||
[/event]
|
||||
)}
|
||||
|
||||
#####
|
||||
# API(s) being tested: [event][filter_attack]type=
|
||||
##
|
||||
# Actions:
|
||||
# Give Alice an ability that adds a damage special with addition of arcane type to all of his weapons.
|
||||
# Give Bob resistance to 50% to arcane
|
||||
# Define events that use filter_attack matching Alice's arcane type.
|
||||
# Have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# The event does not trigger when Alice attacks, because the result is calculated using blade or pierce as the damage type
|
||||
#####
|
||||
{GENERIC_UNIT_TEST event_test_filter_attack_type_no_used (
|
||||
{FILTER_TYPE 50}
|
||||
|
||||
[event]
|
||||
name=turn 2
|
||||
{RETURN ({VARIABLE_CONDITIONAL triggers equals 0})}
|
||||
[/event]
|
||||
)}
|
||||
|
||||
#undef FILTER_TYPE
|
||||
|
||||
#define FILTER_BASE_TYPE TYPE
|
||||
[event]
|
||||
name=start
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=attack
|
||||
set_type=pierce
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=new_ability
|
||||
[abilities]
|
||||
[damage_type]
|
||||
id=test_arcane_damage
|
||||
replacement_type=arcane
|
||||
[/damage_type]
|
||||
[/abilities]
|
||||
[/effect]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
[/object]
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
# Make sure they don't die during the attacks
|
||||
[status]
|
||||
invulnerable=yes
|
||||
[/status]
|
||||
[/modify_unit]
|
||||
{VARIABLE triggers 0}
|
||||
[/event]
|
||||
[event]
|
||||
name=side 1 turn 1
|
||||
[do_command]
|
||||
[move]
|
||||
x=7,13
|
||||
y=3,4
|
||||
[/move]
|
||||
[attack]
|
||||
[source]
|
||||
x,y=13,4
|
||||
[/source]
|
||||
[destination]
|
||||
x,y=13,3
|
||||
[/destination]
|
||||
[/attack]
|
||||
[/do_command]
|
||||
[end_turn][/end_turn]
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
name=side 2 turn
|
||||
[do_command]
|
||||
[attack]
|
||||
[source]
|
||||
x,y=13,3
|
||||
[/source]
|
||||
[destination]
|
||||
x,y=13,4
|
||||
[/destination]
|
||||
[/attack]
|
||||
[/do_command]
|
||||
[end_turn][/end_turn]
|
||||
[/event]
|
||||
|
||||
# Event when Alice attacks
|
||||
[event]
|
||||
name=attack
|
||||
first_time_only=no
|
||||
[filter_attack]
|
||||
base_type={TYPE}
|
||||
[/filter_attack]
|
||||
{ASSERT ({VARIABLE_CONDITIONAL side_number equals 1})}
|
||||
{ASSERT ({VARIABLE_CONDITIONAL triggers equals 0})}
|
||||
{VARIABLE_OP triggers add 1}
|
||||
[/event]
|
||||
#enddef
|
||||
|
||||
#####
|
||||
# API(s) being tested: [event][filter_attack]base_type=
|
||||
##
|
||||
# Actions:
|
||||
# Change Alice attack type to pierce.
|
||||
# Give Alice an ability that adds a damage special with addition of arcane type to all of his weapons.
|
||||
# Define events that use filter_attack matching Alice's pierce original type.
|
||||
# Have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# The event triggers when Alice attacks, because filter matche with pierce original type
|
||||
#####
|
||||
{GENERIC_UNIT_TEST event_test_filter_original_attack_type (
|
||||
{FILTER_BASE_TYPE pierce}
|
||||
|
||||
[event]
|
||||
name=turn 2
|
||||
{RETURN ({VARIABLE_CONDITIONAL triggers equals 1})}
|
||||
[/event]
|
||||
)}
|
||||
|
||||
#####
|
||||
# API(s) being tested: [event][filter_attack]base_type=
|
||||
##
|
||||
# Actions:
|
||||
# Change Alice attack type to pierce.
|
||||
# Give Alice an ability that adds a damage special with addition of arcane type to all of his weapons.
|
||||
# Define events that use filter_attack matching Alice's arcane original type.
|
||||
# Have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# The event does not trigger when Alice attacks, because the original type is pierce
|
||||
#####
|
||||
{GENERIC_UNIT_TEST event_test_filter_attack_base_type_no_match (
|
||||
{FILTER_BASE_TYPE arcane}
|
||||
|
||||
[event]
|
||||
name=turn 2
|
||||
{RETURN ({VARIABLE_CONDITIONAL triggers equals 0})}
|
||||
[/event]
|
||||
)}
|
||||
|
||||
#undef FILTER_BASE_TYPE
|
||||
|
|
|
@ -74,12 +74,8 @@ class unit_adapter {
|
|||
*/
|
||||
int damage_from(const attack_type& attack) const {
|
||||
if(unit_type_ != nullptr) {
|
||||
std::pair<std::string, std::string> types = attack.damage_type();
|
||||
int res = unit_type_->movement_type().resistance_against(types.first);
|
||||
if(!(types.second).empty()){
|
||||
// max not min, resistance_against() returns the percentage taken, so higher means more damage
|
||||
res = std::max(res, unit_type_->movement_type().resistance_against(types.second));
|
||||
}
|
||||
std::string type = attack.effective_damage_type().first;
|
||||
int res = unit_type_->movement_type().resistance_against(type);
|
||||
return res;
|
||||
} else {
|
||||
return unit_->damage_from(attack, false, map_location());
|
||||
|
|
|
@ -87,8 +87,10 @@ variant attack_type_callable::get_value(const std::string& key) const
|
|||
return variant(att_->id());
|
||||
} else if(key == "description") {
|
||||
return variant(att_->name());
|
||||
} else if(key == "type") {
|
||||
} else if(key == "base_type") {
|
||||
return variant(att_->type());
|
||||
} else if(key == "type") {
|
||||
return variant(att_->effective_damage_type().first);
|
||||
} else if(key == "icon") {
|
||||
return variant(att_->icon());
|
||||
} else if(key == "range") {
|
||||
|
@ -133,6 +135,7 @@ void attack_type_callable::get_inputs(formula_input_vector& inputs) const
|
|||
{
|
||||
add_input(inputs, "name");
|
||||
add_input(inputs, "type");
|
||||
add_input(inputs, "base_type");
|
||||
add_input(inputs, "description");
|
||||
add_input(inputs, "icon");
|
||||
add_input(inputs, "range");
|
||||
|
|
|
@ -206,12 +206,7 @@ void attack_predictions::set_data(const combatant_data& attacker, const combatan
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> types = weapon->damage_type();
|
||||
std::string type_bis = types.second;
|
||||
if (!type_bis.empty()) {
|
||||
type_bis = ", " + string_table["type_" + type_bis];
|
||||
}
|
||||
ss << string_table["type_" + types.first] + type_bis;
|
||||
ss << string_table["type_" + weapon->effective_damage_type().first];
|
||||
|
||||
set_label_helper("resis_label", ss.str());
|
||||
|
||||
|
|
|
@ -109,24 +109,16 @@ void unit_attack::pre_show()
|
|||
attacker_itor_->get_location(), false, attacker.weapon
|
||||
);
|
||||
|
||||
std::pair<std::string, std::string> types = attacker_weapon.damage_type();
|
||||
std::string attw_type_second = types.second;
|
||||
std::string attw_type = !(types.first).empty() ? types.first : attacker_weapon.type();
|
||||
std::string types = attacker_weapon.effective_damage_type().first;
|
||||
std::string attw_type = !(types).empty() ? types : attacker_weapon.type();
|
||||
if (!attw_type.empty()) {
|
||||
attw_type = string_table["type_" + attw_type];
|
||||
}
|
||||
if (!attw_type_second.empty()) {
|
||||
attw_type_second = ", " + string_table["type_" + attw_type_second];
|
||||
}
|
||||
std::pair<std::string, std::string> def_types = defender_weapon.damage_type();
|
||||
std::string defw_type_second = def_types.second;
|
||||
std::string defw_type = !(def_types.first).empty() ? def_types.first : defender_weapon.type();
|
||||
std::string def_types = defender_weapon.effective_damage_type().first;
|
||||
std::string defw_type = !(def_types).empty() ? def_types : defender_weapon.type();
|
||||
if (!defw_type.empty()) {
|
||||
defw_type = string_table["type_" + defw_type];
|
||||
}
|
||||
if (!defw_type_second.empty()) {
|
||||
defw_type_second = ", " + string_table["type_" + defw_type_second];
|
||||
}
|
||||
|
||||
const std::set<std::string> checking_tags_other = {"damage_type", "disable", "berserk", "drains", "heal_on_hit", "plague", "slow", "petrifies", "firststrike", "poison"};
|
||||
std::string attw_specials = attacker_weapon.weapon_specials();
|
||||
|
@ -176,26 +168,26 @@ void unit_attack::pre_show()
|
|||
|
||||
// Use attacker/defender.num_blows instead of attacker/defender_weapon.num_attacks() because the latter does not consider the swarm weapon special
|
||||
attacker_stats << markup::bold(attw_name) << "\n"
|
||||
<< attw_type << attw_type_second << "\n"
|
||||
<< attw_type << "\n"
|
||||
<< attacker.damage << font::weapon_numbers_sep << attacker.num_blows
|
||||
<< attw_specials << "\n"
|
||||
<< markup::span_color(a_cth_color, attacker.chance_to_hit, "%");
|
||||
|
||||
attacker_tooltip << _("Weapon: ") << markup::bold(attw_name) << "\n"
|
||||
<< _("Type: ") << attw_type << attw_type_second << "\n"
|
||||
<< _("Type: ") << attw_type << "\n"
|
||||
<< _("Damage: ") << attacker.damage << markup::italic(attw_specials_dmg) << "\n"
|
||||
<< _("Attacks: ") << attacker.num_blows << markup::italic(attw_specials_atk) << "\n"
|
||||
<< _("Chance to hit: ") << markup::span_color(a_cth_color, attacker.chance_to_hit, "%")
|
||||
<< markup::italic(attw_specials_cth) << attw_specials_others;
|
||||
|
||||
defender_stats << markup::bold(defw_name) << "\n"
|
||||
<< defw_type << defw_type_second << "\n"
|
||||
<< defw_type << "\n"
|
||||
<< defender.damage << font::weapon_numbers_sep << defender.num_blows
|
||||
<< defw_specials << "\n"
|
||||
<< markup::span_color(d_cth_color, defender.chance_to_hit, "%");
|
||||
|
||||
defender_tooltip << _("Weapon: ") << markup::bold(defw_name) << "\n"
|
||||
<< _("Type: ") << defw_type << defw_type_second << "\n"
|
||||
<< _("Type: ") << defw_type << "\n"
|
||||
<< _("Damage: ") << defender.damage << markup::italic(defw_specials_dmg) << "\n"
|
||||
<< _("Attacks: ") << defender.num_blows << markup::italic(defw_specials_atk) << "\n"
|
||||
<< _("Chance to hit: ") << markup::span_color(d_cth_color, defender.chance_to_hit, "%")
|
||||
|
|
|
@ -873,8 +873,9 @@ static int attack_info(const reports::context& rc, const attack_type &at, config
|
|||
const string_with_tooltip damage_and_num_attacks {flush(str), flush(tooltip)};
|
||||
|
||||
std::string range = string_table["range_" + at.range()];
|
||||
std::string type = at.damage_type().first;
|
||||
std::set<std::string> alt_types = at.alternative_damage_types();
|
||||
std::pair<std::string, std::set<std::string>> all_damage_types = at.damage_types();
|
||||
std::string type = all_damage_types.first;
|
||||
std::set<std::string> alt_types = all_damage_types.second;
|
||||
std::string lang_type = string_table["type_" + type];
|
||||
for(auto alt_t : alt_types){
|
||||
lang_type += ", " + string_table["type_" + alt_t];
|
||||
|
|
|
@ -1258,7 +1258,7 @@ void attack_type::modified_attacks(unsigned & min_attacks,
|
|||
}
|
||||
}
|
||||
|
||||
static std::string select_replacement_type(const unit_ability_list& damage_type_list)
|
||||
std::string attack_type::select_replacement_type(const unit_ability_list& damage_type_list) const
|
||||
{
|
||||
std::map<std::string, unsigned int> type_count;
|
||||
unsigned int max = 0;
|
||||
|
@ -1273,7 +1273,7 @@ static std::string select_replacement_type(const unit_ability_list& damage_type_
|
|||
}
|
||||
}
|
||||
|
||||
if (type_count.empty()) return "";
|
||||
if (type_count.empty()) return type();
|
||||
|
||||
std::vector<std::string> type_list;
|
||||
for(auto& i : type_count){
|
||||
|
@ -1282,27 +1282,29 @@ static std::string select_replacement_type(const unit_ability_list& damage_type_
|
|||
}
|
||||
}
|
||||
|
||||
if(type_list.empty()) return "";
|
||||
if(type_list.empty()) return type();
|
||||
|
||||
return type_list.front();
|
||||
}
|
||||
|
||||
static std::string select_alternative_type(const unit_ability_list& damage_type_list, const unit_ability_list& resistance_list, const unit& u)
|
||||
std::pair<std::string, int> attack_type::select_alternative_type(const unit_ability_list& damage_type_list, const unit_ability_list& resistance_list) const
|
||||
{
|
||||
std::map<std::string, int> type_res;
|
||||
int max_res = std::numeric_limits<int>::min();
|
||||
for(auto& i : damage_type_list) {
|
||||
const config& c = *i.ability_cfg;
|
||||
if(c.has_attribute("alternative_type")) {
|
||||
std::string type = c["alternative_type"].str();
|
||||
if(type_res.count(type) == 0){
|
||||
type_res[type] = u.resistance_value(resistance_list, type);
|
||||
max_res = std::max(max_res, type_res[type]);
|
||||
int max_res = INT_MIN;
|
||||
if(other_){
|
||||
for(auto& i : damage_type_list) {
|
||||
const config& c = *i.ability_cfg;
|
||||
if(c.has_attribute("alternative_type")) {
|
||||
std::string type = c["alternative_type"].str();
|
||||
if(type_res.count(type) == 0){
|
||||
type_res[type] = (*other_).resistance_value(resistance_list, type);
|
||||
max_res = std::max(max_res, type_res[type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type_res.empty()) return "";
|
||||
if (type_res.empty()) return {"", INT_MIN};
|
||||
|
||||
std::vector<std::string> type_list;
|
||||
for(auto& i : type_res){
|
||||
|
@ -1310,66 +1312,63 @@ static std::string select_alternative_type(const unit_ability_list& damage_type_
|
|||
type_list.push_back(i.first);
|
||||
}
|
||||
}
|
||||
if(type_list.empty()) return "";
|
||||
if(type_list.empty()) return {"", INT_MIN};
|
||||
|
||||
return type_list.front();
|
||||
}
|
||||
|
||||
std::string attack_type::select_damage_type(const unit_ability_list& damage_type_list, const std::string& key_name, const unit_ability_list& resistance_list) const
|
||||
{
|
||||
bool is_alternative = (key_name == "alternative_type");
|
||||
if(is_alternative && other_){
|
||||
return select_alternative_type(damage_type_list, resistance_list, (*other_));
|
||||
} else if(!is_alternative){
|
||||
return select_replacement_type(damage_type_list);
|
||||
}
|
||||
return "";
|
||||
return {type_list.front(), max_res};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of damage inflicted.
|
||||
* The type of attack used and the resistance value that does the most damage.
|
||||
*/
|
||||
std::pair<std::string, std::string> attack_type::damage_type() const
|
||||
std::pair<std::string, int> attack_type::effective_damage_type() const
|
||||
{
|
||||
if(attack_empty()){
|
||||
return {"", ""};
|
||||
return {"", 100};
|
||||
}
|
||||
unit_ability_list damage_type_list = get_specials_and_abilities("damage_type");
|
||||
if(damage_type_list.empty()){
|
||||
return {type(), ""};
|
||||
}
|
||||
|
||||
unit_ability_list resistance_list;
|
||||
if(other_){
|
||||
resistance_list = (*other_).get_abilities_weapons("resistance", other_loc_, other_attack_, shared_from_this());
|
||||
utils::erase_if(resistance_list, [&](const unit_ability& i) {
|
||||
return (!((*i.ability_cfg)["active_on"].empty() || (!is_attacker_ && (*i.ability_cfg)["active_on"] == "offense") || (is_attacker_ && (*i.ability_cfg)["active_on"] == "defense")));
|
||||
});
|
||||
}
|
||||
std::string replacement_type = select_damage_type(damage_type_list, "replacement_type", resistance_list);
|
||||
std::string alternative_type = select_damage_type(damage_type_list, "alternative_type", resistance_list);
|
||||
std::string type_damage = replacement_type.empty() ? type() : replacement_type;
|
||||
if(!alternative_type.empty() && type_damage != alternative_type){
|
||||
return {type_damage, alternative_type};
|
||||
unit_ability_list damage_type_list = get_specials_and_abilities("damage_type");
|
||||
int res = other_ ? (*other_).resistance_value(resistance_list, type()) : 100;
|
||||
if(damage_type_list.empty()){
|
||||
return {type(), res};
|
||||
}
|
||||
return {type_damage, ""};
|
||||
std::string replacement_type = select_replacement_type(damage_type_list);
|
||||
std::pair<std::string, int> alternative_type = select_alternative_type(damage_type_list, resistance_list);
|
||||
|
||||
if(other_){
|
||||
res = replacement_type != type() ? (*other_).resistance_value(resistance_list, replacement_type) : res;
|
||||
replacement_type = alternative_type.second > res ? alternative_type.first : replacement_type;
|
||||
res = std::max(res, alternative_type.second);
|
||||
}
|
||||
return {replacement_type, res};
|
||||
}
|
||||
|
||||
std::set<std::string> attack_type::alternative_damage_types() const
|
||||
/**
|
||||
* Return a type()/replacement_type and a list of alternative_types that should be displayed in the selected unit's report.
|
||||
*/
|
||||
std::pair<std::string, std::set<std::string>> attack_type::damage_types() const
|
||||
{
|
||||
unit_ability_list damage_type_list = get_specials_and_abilities("damage_type");
|
||||
std::set<std::string> alternative_damage_types;
|
||||
if(damage_type_list.empty()){
|
||||
return {};
|
||||
return {type(), alternative_damage_types};
|
||||
}
|
||||
std::set<std::string> damage_types;
|
||||
std::string replacement_type = select_replacement_type(damage_type_list);
|
||||
for(auto& i : damage_type_list) {
|
||||
const config& c = *i.ability_cfg;
|
||||
if(c.has_attribute("alternative_type")){
|
||||
damage_types.insert(c["alternative_type"].str());
|
||||
alternative_damage_types.insert(c["alternative_type"].str());
|
||||
}
|
||||
}
|
||||
|
||||
return damage_types;
|
||||
return {replacement_type, alternative_damage_types};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the damage per attack of this weapon, considering specials.
|
||||
*/
|
||||
|
|
|
@ -116,6 +116,7 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
const std::set<std::string> filter_alignment = utils::split_set(filter["alignment"].str());
|
||||
const std::set<std::string> filter_name = utils::split_set(filter["name"].str());
|
||||
const std::set<std::string> filter_type = utils::split_set(filter["type"].str());
|
||||
const std::set<std::string> filter_base_type = utils::split_set(filter["base_type"].str());
|
||||
const std::vector<std::string> filter_special = utils::split(filter["special"]);
|
||||
const std::vector<std::string> filter_special_id = utils::split(filter["special_id"]);
|
||||
const std::vector<std::string> filter_special_type = utils::split(filter["special_type"]);
|
||||
|
@ -168,13 +169,15 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
}
|
||||
} else {
|
||||
//if the type is different from "damage_type" then damage_type() can be called for safe checking.
|
||||
std::pair<std::string, std::string> damage_type = attack.damage_type();
|
||||
if (filter_type.count(damage_type.first) == 0 && filter_type.count(damage_type.second) == 0){
|
||||
if (filter_type.count(attack.effective_damage_type().first) == 0){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !filter_base_type.empty() && filter_base_type.count(attack.type()) == 0 )
|
||||
return false;
|
||||
|
||||
if(!filter_special.empty()) {
|
||||
deprecated_message("special=", DEP_LEVEL::PREEMPTIVE, {1, 17, 0}, "Please use special_id or special_type instead");
|
||||
bool found = false;
|
||||
|
|
|
@ -98,18 +98,10 @@ public:
|
|||
void modified_attacks(unsigned & min_attacks,
|
||||
unsigned & max_attacks) const;
|
||||
|
||||
/**
|
||||
* Select best damage type based on frequency count for replacement_type and based on highest damage for alternative_type.
|
||||
*
|
||||
* @param damage_type_list list of [damage_type] to check.
|
||||
* @param key_name name of attribute checked 'alternative_type' or 'replacement_type'.
|
||||
* @param resistance_list list of "resistance" abilities to check for each type of damage checked.
|
||||
*/
|
||||
std::string select_damage_type(const unit_ability_list& damage_type_list, const std::string& key_name, const unit_ability_list& resistance_list) const;
|
||||
/** return a modified damage type and/or add a secondary_type for hybrid use if special is active. */
|
||||
std::pair<std::string, std::string> damage_type() const;
|
||||
/** @return A list of alternative_type damage types. */
|
||||
std::set<std::string> alternative_damage_types() const;
|
||||
/** @return A type()/replacement_type and a list of alternative_types that should be displayed in the selected unit's report. */
|
||||
std::pair<std::string, std::set<std::string>> damage_types() const;
|
||||
/** @return The type of attack used and the resistance value that does the most damage. */
|
||||
std::pair<std::string, int> effective_damage_type() const;
|
||||
|
||||
/** Returns the damage per attack of this weapon, considering specials. */
|
||||
double modified_damage() const;
|
||||
|
@ -235,6 +227,19 @@ private:
|
|||
* @return true if all attribute with ability checked
|
||||
*/
|
||||
bool special_matches_filter(const config & cfg, const std::string& tag_name, const config & filter) const;
|
||||
/**
|
||||
* Select best damage type based on frequency count for replacement_type.
|
||||
*
|
||||
* @param damage_type_list list of [damage_type] to check.
|
||||
*/
|
||||
std::string select_replacement_type(const unit_ability_list& damage_type_list) const;
|
||||
/**
|
||||
* Select best damage type based on highest damage for alternative_type.
|
||||
*
|
||||
* @param damage_type_list list of [damage_type] to check.
|
||||
* @param resistance_list list of "resistance" abilities to check for each type of damage checked.
|
||||
*/
|
||||
std::pair<std::string, int> select_alternative_type(const unit_ability_list& damage_type_list, const unit_ability_list& resistance_list) const;
|
||||
/**
|
||||
* Filter a list of abilities or weapon specials, removing any entries that don't own
|
||||
* the overwrite_specials attributes.
|
||||
|
|
|
@ -1772,25 +1772,13 @@ static bool resistance_filter_matches_base(const config& cfg, bool attacker)
|
|||
|
||||
int unit::resistance_against(const std::string& damage_name, bool attacker, const map_location& loc, const_attack_ptr weapon, const const_attack_ptr& opp_weapon) const
|
||||
{
|
||||
if(opp_weapon){
|
||||
return opp_weapon->effective_damage_type().second;
|
||||
}
|
||||
unit_ability_list resistance_list = get_abilities_weapons("resistance",loc, std::move(weapon), opp_weapon);
|
||||
utils::erase_if(resistance_list, [&](const unit_ability& i) {
|
||||
return !resistance_filter_matches_base(*i.ability_cfg, attacker);
|
||||
});
|
||||
if(opp_weapon){
|
||||
unit_ability_list damage_type_list = opp_weapon->get_specials_and_abilities("damage_type");
|
||||
if(damage_type_list.empty()){
|
||||
return resistance_value(resistance_list, damage_name);
|
||||
}
|
||||
std::string replacement_type = opp_weapon->select_damage_type(damage_type_list, "replacement_type", resistance_list);
|
||||
std::string type_damage = replacement_type.empty() ? damage_name : replacement_type;
|
||||
int max_res = resistance_value(resistance_list, type_damage);
|
||||
for(auto& i : damage_type_list) {
|
||||
if((*i.ability_cfg).has_attribute("alternative_type")){
|
||||
max_res = std::max(max_res , resistance_value(resistance_list, (*i.ability_cfg)["alternative_type"].str()));
|
||||
}
|
||||
}
|
||||
return max_res;
|
||||
}
|
||||
return resistance_value(resistance_list, damage_name);
|
||||
}
|
||||
|
||||
|
|
|
@ -168,6 +168,9 @@
|
|||
0 event_test_filter_attack
|
||||
0 event_test_filter_attack_no_defense
|
||||
0 event_test_filter_attack_type
|
||||
0 event_test_filter_attack_type_no_used
|
||||
0 event_test_filter_original_attack_type
|
||||
0 event_test_filter_attack_base_type_no_match
|
||||
0 event_test_filter_attack_specials
|
||||
0 event_test_filter_attack_on_moveto
|
||||
0 event_test_filter_attack_opponent_weapon_condition
|
||||
|
|
Loading…
Reference in New Issue
Block a user