add min_value to [resistance] (#8722)
max_value is used to limit the increase in resistance with the "resistance" capability, but there was no equivalent for its reduction. To be able to add min_value without redoing the "resistance" checking for the umpteenth time, I prefer to modify effect:: so that the checking of these two attributes is done at the same time as the other numerical attributes and keep the door open to a possible generalization of the proceed
This commit is contained in:
parent
f5c8db7b2f
commit
82499d0785
7 changed files with 62 additions and 19 deletions
|
@ -80,6 +80,7 @@
|
|||
{SIMPLE_KEY apply_to string}
|
||||
{SIMPLE_KEY active_on ability_context}
|
||||
{SIMPLE_KEY max_value f_int}
|
||||
{SIMPLE_KEY min_value f_int}
|
||||
{FILTER_TAG "filter_weapon" weapon ()}
|
||||
{FILTER_TAG "filter_second_weapon" weapon ()}
|
||||
[/tag]
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# wmllint: no translatables
|
||||
|
||||
#####
|
||||
# API(s) being tested: [resistance]min_value=
|
||||
##
|
||||
# Actions:
|
||||
# Give all units resistance to all damage types with a value of 10 but a min_value of 30
|
||||
# Attack each other
|
||||
##
|
||||
# Expected end state:
|
||||
# The damage from the attack is reduced by 30%
|
||||
#####
|
||||
{COMMON_KEEP_A_B_UNIT_TEST "resistance_min_value" (
|
||||
[event]
|
||||
name = start
|
||||
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to = new_ability
|
||||
[abilities]
|
||||
{TEST_ABILITY resistance 10 (min_value=30) SELF=yes}
|
||||
[/abilities]
|
||||
[/effect]
|
||||
[/modify_unit]
|
||||
|
||||
{ATTACK_AND_VALIDATE 70}
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
)}
|
|
@ -1575,7 +1575,7 @@ void attack_unit_and_advance(const map_location& attacker,
|
|||
int under_leadership(const unit &u, const map_location& loc, const_attack_ptr weapon, const_attack_ptr opp_weapon)
|
||||
{
|
||||
unit_ability_list abil = u.get_abilities_weapons("leadership", loc, weapon, opp_weapon);
|
||||
unit_abilities::effect leader_effect(abil, 0, nullptr, true);
|
||||
unit_abilities::effect leader_effect(abil, 0, nullptr, unit_abilities::EFFECT_CUMULABLE);
|
||||
return leader_effect.get_composite_value();
|
||||
}
|
||||
|
||||
|
|
|
@ -1919,18 +1919,20 @@ bool filter_base_matches(const config& cfg, int def)
|
|||
return true;
|
||||
}
|
||||
|
||||
effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, bool is_cumulable) :
|
||||
effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, EFFECTS wham) :
|
||||
effect_list_(),
|
||||
composite_value_(0)
|
||||
{
|
||||
|
||||
int value_set = is_cumulable ? std::max(list.highest("value").first, 0) + std::min(list.lowest("value").first, 0) : def;
|
||||
int value_set = (wham == EFFECT_CUMULABLE) ? std::max(list.highest("value").first, 0) + std::min(list.lowest("value").first, 0) : def;
|
||||
std::map<std::string,individual_effect> values_add;
|
||||
std::map<std::string,individual_effect> values_mul;
|
||||
std::map<std::string,individual_effect> values_div;
|
||||
|
||||
individual_effect set_effect_max;
|
||||
individual_effect set_effect_min;
|
||||
std::optional<int> max_value = std::nullopt;
|
||||
std::optional<int> min_value = std::nullopt;
|
||||
|
||||
for (const unit_ability & ability : list) {
|
||||
const config& cfg = *ability.ability_cfg;
|
||||
|
@ -1939,7 +1941,7 @@ effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, boo
|
|||
if (!filter_base_matches(cfg, def))
|
||||
continue;
|
||||
|
||||
if(!is_cumulable){
|
||||
if(wham != EFFECT_CUMULABLE){
|
||||
if (const config::attribute_value *v = cfg.get("value")) {
|
||||
int value = get_single_ability_value(*v, def, ability, list.loc(), att, [&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
|
||||
callable.add("base_value", wfl::variant(def));
|
||||
|
@ -1963,6 +1965,15 @@ effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, boo
|
|||
}
|
||||
}
|
||||
|
||||
if(wham == EFFECT_CLAMP_MIN_MAX){
|
||||
if(cfg.has_attribute("max_value")){
|
||||
max_value = max_value ? std::min(*max_value, cfg["max_value"].to_int()) : cfg["max_value"].to_int();
|
||||
}
|
||||
if(cfg.has_attribute("min_value")){
|
||||
min_value = min_value ? std::max(*min_value, cfg["min_value"].to_int()) : cfg["min_value"].to_int();
|
||||
}
|
||||
}
|
||||
|
||||
if (const config::attribute_value *v = cfg.get("add")) {
|
||||
int add = get_single_ability_value(*v, def, ability, list.loc(), att, [&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
|
||||
callable.add("base_value", wfl::variant(def));
|
||||
|
@ -2011,7 +2022,7 @@ effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, boo
|
|||
}
|
||||
}
|
||||
|
||||
if(!is_cumulable && set_effect_max.type != NOT_USED) {
|
||||
if((wham != EFFECT_CUMULABLE) && set_effect_max.type != NOT_USED) {
|
||||
value_set = std::max(set_effect_max.value, 0) + std::min(set_effect_min.value, 0);
|
||||
if(set_effect_max.value > def) {
|
||||
effect_list_.push_back(set_effect_max);
|
||||
|
@ -2049,6 +2060,14 @@ effect::effect(const unit_ability_list& list, int def, const_attack_ptr att, boo
|
|||
}
|
||||
|
||||
composite_value_ = static_cast<int>((value_set + addition) * multiplier / divisor);
|
||||
//clamp what if min_value < max_value or one attribute only used.
|
||||
if(max_value && min_value && *min_value < *max_value) {
|
||||
composite_value_ = std::clamp(*min_value, *max_value, composite_value_);
|
||||
} else if(max_value && !min_value) {
|
||||
composite_value_ = std::min(*max_value, composite_value_);
|
||||
} else if(min_value && !max_value) {
|
||||
composite_value_ = std::max(*min_value, composite_value_);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace unit_abilities
|
||||
|
|
|
@ -25,6 +25,8 @@ bool filter_base_matches(const config& cfg, int def);
|
|||
|
||||
enum value_modifier {NOT_USED,SET,ADD,MUL,DIV};
|
||||
|
||||
enum EFFECTS { EFFECT_DEFAULT=1, EFFECT_CUMULABLE=2, EFFECT_CLAMP_MIN_MAX=3 };
|
||||
|
||||
struct individual_effect
|
||||
{
|
||||
individual_effect() : type(NOT_USED), value(0), ability(nullptr),
|
||||
|
@ -39,7 +41,7 @@ struct individual_effect
|
|||
class effect
|
||||
{
|
||||
public:
|
||||
effect(const unit_ability_list& list, int def, const_attack_ptr attacker = const_attack_ptr(), bool is_cumulable = false);
|
||||
effect(const unit_ability_list& list, int def, const_attack_ptr attacker = const_attack_ptr(), EFFECTS wham = EFFECT_DEFAULT);
|
||||
// Provide read-only access to the effect list:
|
||||
typedef std::vector<individual_effect>::const_iterator iterator;
|
||||
typedef std::vector<individual_effect>::const_iterator const_iterator;
|
||||
|
|
|
@ -1800,21 +1800,10 @@ int unit::resistance_ability(unit_ability_list resistance_abilities, const std::
|
|||
});
|
||||
|
||||
if(!resistance_abilities.empty()) {
|
||||
unit_abilities::effect resist_effect(resistance_abilities, 100-res);
|
||||
unit_abilities::effect resist_effect(resistance_abilities, 100-res, nullptr, unit_abilities::EFFECT_CLAMP_MIN_MAX);
|
||||
|
||||
unit_ability_list resistance_max_value;
|
||||
resistance_max_value.append_if(resistance_abilities, [&](const unit_ability& i) {
|
||||
return (*i.ability_cfg).has_attribute("max_value");
|
||||
});
|
||||
if(!resistance_max_value.empty()){
|
||||
res = 100 - std::min<int>(
|
||||
resist_effect.get_composite_value(),
|
||||
resistance_max_value.highest("max_value").first
|
||||
);
|
||||
} else {
|
||||
res = 100 - resist_effect.get_composite_value();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -600,6 +600,7 @@
|
|||
0 resistance_two_cumulative_mixed_same_id
|
||||
0 resistance_two_cumulative_mixed_unique_id
|
||||
0 resistance_max_value
|
||||
0 resistance_min_value
|
||||
0 resistance_negative_max_value
|
||||
0 resistance_apply_to_blade
|
||||
0 resistance_apply_to_non_blade
|
||||
|
|
Loading…
Add table
Reference in a new issue