Fix attack::damage_type bug for ability resistance

When [damage_type] is used but the opponent uses the resistance ability
against the added type, the ability filter only detected the original type and
the new type was not affected.
This commit is contained in:
newfrenchy83 2024-04-04 18:01:36 +02:00 committed by GitHub
parent c66b6d6c85
commit 57c8e0cce0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 171 additions and 4 deletions

View file

@ -0,0 +1,138 @@
# wmllint: no translatables
#####
# API(s) being tested: [resistance]apply_to= when opponent use [damage_type]alternative_type=
##
# Actions:
# Give all units vulnerability to arcane damage with a value of -100%
# Attack each other with blade,arcane weapons
##
# Expected end state:
# The damage from the attack is increased by 100%
#####
{COMMON_KEEP_A_B_UNIT_TEST "negative_resistance_with_two_attack_types" (
[event]
name = start
[modify_unit]
[filter]
[/filter]
[effect]
apply_to = new_ability
[abilities]
{TEST_ABILITY resistance -100 (max_value=100
apply_to=arcane) SELF=yes}
[/abilities]
[/effect]
[effect]
apply_to=attack
[set_specials]
mode=append
[damage_type]
alternative_type=arcane
[/damage_type]
[/set_specials]
[/effect]
[/modify_unit]
{ATTACK_AND_VALIDATE 200}
{SUCCEED}
[/event]
) SIDE1_LEADER="Orcish Grunt"}
#####
# API(s) being tested: [resistance]apply_to= when opponent use [damage_type]alternative_type=
##
# Actions:
# Give all units resistance to arcane damage with a value of 50%
# Attack each other with blade,arcane weapons
##
# Expected end state:
# The damage from the attack is not changed because blade does more damage than arcane
#####
{COMMON_KEEP_A_B_UNIT_TEST "positive_resistance_with_two_attack_types" (
[event]
name = start
[modify_unit]
[filter]
[/filter]
[effect]
apply_to = new_ability
[abilities]
{TEST_ABILITY resistance 50 (max_value=50
apply_to=arcane) SELF=yes}
[/abilities]
[/effect]
[effect]
apply_to=attack
[set_specials]
mode=append
[damage_type]
alternative_type=arcane
[/damage_type]
[/set_specials]
[/effect]
[/modify_unit]
{ATTACK_AND_VALIDATE 100}
{SUCCEED}
[/event]
) SIDE1_LEADER="Orcish Grunt"}
#####
# API(s) being tested: [damage_type]alternative_type=
##
# Actions:
# Bob is a Skeleton, with resistance to blade but weakness to arcane
# Give Alice's attacks alternative_type=arcane
# Make Alice teach anti-magic, so that Bob's resistance to arcane is more than his resistance to blade
# Have Alice attack Bob
##
# Expected end state:
# Alice attacked using the blade stats, not the arcane ones.
#####
{COMMON_KEEP_A_B_UNIT_TEST "taught_resistance_with_two_attack_types" (
[event]
name = start
[modify_unit]
[filter]
id=alice
[/filter]
[effect]
apply_to=attack
[set_specials]
mode=replace
[damage_type]
alternative_type=arcane
[/damage_type]
[/set_specials]
[/effect]
[effect]
apply_to=new_ability
# An ability which reduces damage to both friend and foe, based on the anti-magi aura of EoMa's Matriarch of Emptiness
# This doesn't use the TEST_ABILITY macro, because it tests add= rather than value=
[abilities]
[resistance]
add=70
max_value=70
apply_to=fire,cold,arcane
affect_self=no
affect_allies=yes
affect_enemies=yes
[affect_adjacent]
[/affect_adjacent]
[filter_base_value]
less_than=70
[/filter_base_value]
[/resistance]
[/abilities]
[/effect]
[/modify_unit]
# Skeletons have base +40% vs blade, -20% vs arcane. With the +70% buff, is weaker to blade than arcane.
{ATTACK_AND_VALIDATE 100 DAMAGE2=60}
{SUCCEED}
[/event]
) SIDE2_LEADER=Skeleton}

View file

@ -1789,11 +1789,9 @@ bool unit::resistance_filter_matches(const config& cfg, bool attacker, const std
return true;
}
int unit::resistance_against(const std::string& damage_name,bool attacker,const map_location& loc, const_attack_ptr weapon, const_attack_ptr opp_weapon) const
int unit::resistance_ability(unit_ability_list resistance_abilities, const std::string& damage_name, bool attacker) const
{
int res = opp_weapon ? movement_type_.resistance_against(*opp_weapon) : movement_type_.resistance_against(damage_name);
unit_ability_list resistance_abilities = get_abilities_weapons("resistance",loc, weapon, opp_weapon);
int res = movement_type_.resistance_against(damage_name);
utils::erase_if(resistance_abilities, [&](const unit_ability& i) {
return !resistance_filter_matches(*i.ability_cfg, attacker, damage_name, 100-res);
});
@ -1818,6 +1816,24 @@ int unit::resistance_against(const std::string& damage_name,bool attacker,const
return res;
}
int unit::resistance_against(const std::string& damage_name,bool attacker,const map_location& loc, const_attack_ptr weapon, const_attack_ptr opp_weapon) const
{
std::pair<std::string, std::string> types;
if(opp_weapon){
types = opp_weapon->damage_type();
} else{
types.first = damage_name;
}
unit_ability_list resistance_abilities = get_abilities_weapons("resistance",loc, weapon, opp_weapon);
int res = resistance_ability(resistance_abilities, types.first, attacker);
if(!(types.second).empty()){
res = std::max(res , resistance_ability(resistance_abilities, types.second, attacker));
}
return res;
}
std::map<std::string, std::string> unit::advancement_icons() const
{
std::map<std::string,std::string> temp;

View file

@ -1054,6 +1054,16 @@ public:
private:
bool resistance_filter_matches(const config& cfg, bool attacker, const std::string& damage_name, int res) const;
/**
* For the provided list of resistance abilities, determine the damage resistance based on which are active and any max_value that's present.
*
* @param resistance_abilities A list of resistance abilities that the unit has.
* @param damage_name The name of the damage type, for example "blade".
* @param attacker True if the unit is attacking, false if defending.
* @return The resistance value for a unit with the provided resistance abilities to the provided damage type.
*/
int resistance_ability(unit_ability_list resistance_abilities, const std::string& damage_name, bool attacker) const;
/**
* @}
* @defgroup unit_trait Trait and upkeep functions

View file

@ -369,6 +369,9 @@
0 damage_type_test
0 damage_type_with_filter_test
0 damage_secondary_type_test
0 negative_resistance_with_two_attack_types
0 positive_resistance_with_two_attack_types
0 taught_resistance_with_two_attack_types
0 swarms_filter_student_by_type
0 swarms_effects_not_checkable
0 filter_special_id_active