diff --git a/changelog.md b/changelog.md index 2639092fed0..c713c0ed7d3 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,7 @@ * Text labels now use the hyperlink mouse cursor while hovering links. * Link awareness is now configured on a per-instance basis for labels/scroll labels instead of globally in their definition. ### WML Engine + * Add a overwrite_specials option for abilities like weapon could overwrite specials or other ablities like weapon ### Miscellaneous and Bug Fixes * Fixed several possible crashes in wmllint diff --git a/data/core/macros/utils.cfg b/data/core/macros/utils.cfg index e4d5f45f747..2ae118b29ea 100644 --- a/data/core/macros/utils.cfg +++ b/data/core/macros/utils.cfg @@ -554,6 +554,7 @@ value={CTH_NUMBER} cumulative=no affect_self=yes + overwrite_specials=yes [filter_opponent] {SECOND_FILTER} [/filter_opponent] @@ -606,6 +607,7 @@ value={CTH_NUMBER} cumulative=no affect_self=yes + overwrite_specials=yes [filter_opponent] {SECOND_FILTER} [/filter_opponent] diff --git a/data/schema/units/abilities.cfg b/data/schema/units/abilities.cfg index 442872461ab..2aadd30e07c 100644 --- a/data/schema/units/abilities.cfg +++ b/data/schema/units/abilities.cfg @@ -5,6 +5,7 @@ max=infinite super="units/unit_type/abilities/~generic~,units/unit_type/attack/specials/" + {NAME} {FILTER_TAG "filter_student" unit {FILTER_TAG "filter_weapon" weapon ()}} + {SIMPLE_KEY overwrite_specials bool} [/tag] #enddef diff --git a/data/test/scenarios/test_force_chance_to_hit_macro.cfg b/data/test/scenarios/test_force_chance_to_hit_macro.cfg new file mode 100644 index 00000000000..92c16c428f1 --- /dev/null +++ b/data/test/scenarios/test_force_chance_to_hit_macro.cfg @@ -0,0 +1,118 @@ +# This unit test defines a WML object based implementation of the "unupgradable" ability +# https://github.com/ProditorMagnus/Ageless-for-1-14/blob/52c1eaf31722bb58046a1b459d4f29daa8d88487/data/general_data/weapon_specials/unupgradable.cfg +# and checks that it works. What is being tested here is that +# FORCE_CHANCE_TO_HIT macro must doing misses all attacks then what [chance_to_hit] value equals 100% +# - through [attacks] +# - through [effect] increase_attacks + +{GENERIC_UNIT_TEST "test_force_chance_to_hit_macro" ( + {FORCE_CHANCE_TO_HIT (id=bob) (id=alice) 0 ()} + {FORCE_CHANCE_TO_HIT (id=alice) (id=bob) 0 ()} + [event] + name=start + [modify_unit] + [filter] + [/filter] + max_hitpoints=100 + hitpoints=100 + attacks_left=1 + [/modify_unit] + [object] + silent=yes + [effect] + apply_to=attack + [set_specials] + mode=append + [attacks] + value=10 + [/attacks] + [attacks] + add=13 + [/attacks] + [damage] + value=1 + [/damage] + [chance_to_hit] + value=100 + [/chance_to_hit] + [/set_specials] + [/effect] + [filter] + id=bob + [/filter] + [/object] + [object] + silent=yes + [effect] + apply_to=attack + [set_specials] + mode=append + [attacks] + value=10 + [/attacks] + [damage] + value=1 + [/damage] + [chance_to_hit] + value=100 + [/chance_to_hit] + [/set_specials] + [/effect] + [filter] + id=alice + [/filter] + [/object] + [store_unit] + [filter] + id=alice + [/filter] + variable=a + kill=yes + [/store_unit] + [store_unit] + [filter] + id=bob + [/filter] + variable=b + [/store_unit] + [unstore_unit] + variable=a + find_vacant=yes + x,y=$b.x,$b.y + [/unstore_unit] + [store_unit] + [filter] + id=alice + [/filter] + variable=a + [/store_unit] + + [do_command] + [attack] + weapon=0 + defender_weapon=0 + [source] + x,y=$a.x,$a.y + [/source] + [destination] + x,y=$b.x,$b.y + [/destination] + [/attack] + [/do_command] + [store_unit] + [filter] + id=alice + [/filter] + variable=a + [/store_unit] + [store_unit] + [filter] + id=bob + [/filter] + variable=b + [/store_unit] + {ASSERT ({VARIABLE_CONDITIONAL a.hitpoints equals 100})} + {ASSERT ({VARIABLE_CONDITIONAL b.hitpoints equals 100})} + {SUCCEED} + [/event] +)} diff --git a/src/units/abilities.cpp b/src/units/abilities.cpp index 0f3072b605f..565404c2fe0 100644 --- a/src/units/abilities.cpp +++ b/src/units/abilities.cpp @@ -1117,23 +1117,44 @@ unit_ability_list attack_type::list_ability(const std::string& ability) const if(self_) { abil_list.append((*self_).get_abilities(ability, self_loc_)); for(unit_ability_list::iterator i = abil_list.begin(); i != abil_list.end();) { - if(!special_active(*i->ability_cfg, AFFECT_SELF, ability, true, "filter_student")) { + if(!((*i->ability_cfg)["overwrite_specials"].to_bool() && special_active(*i->ability_cfg, AFFECT_SELF, ability, true, "filter_student"))) { i = abil_list.erase(i); } else { ++i; } } + + if(abil_list.empty()){ + abil_list.append((*self_).get_abilities(ability, self_loc_)); + for(unit_ability_list::iterator i = abil_list.begin(); i != abil_list.end();) { + if(!special_active(*i->ability_cfg, AFFECT_SELF, ability, true, "filter_student")) { + i = abil_list.erase(i); + } else { + ++i; + } + } + } } if(other_) { abil_other_list.append((*other_).get_abilities(ability, other_loc_)); for(unit_ability_list::iterator i = abil_other_list.begin(); i != abil_other_list.end();) { - if(!special_active_impl(other_attack_, shared_from_this(), *i->ability_cfg, AFFECT_OTHER, ability, true, "filter_student")) { + if(!((*i->ability_cfg)["overwrite_specials"].to_bool() && special_active_impl(other_attack_, shared_from_this(), *i->ability_cfg, AFFECT_OTHER, ability, true, "filter_student"))) { i = abil_other_list.erase(i); } else { ++i; } } + if(abil_other_list.empty()){ + abil_other_list.append((*other_).get_abilities(ability, other_loc_)); + for(unit_ability_list::iterator i = abil_other_list.begin(); i != abil_other_list.end();) { + if(!special_active_impl(other_attack_, shared_from_this(), *i->ability_cfg, AFFECT_OTHER, ability, true, "filter_student")) { + i = abil_other_list.erase(i); + } else { + ++i; + } + } + } } abil_list.append(abil_other_list); return abil_list; @@ -1142,6 +1163,12 @@ unit_ability_list attack_type::list_ability(const std::string& ability) const unit_ability_list attack_type::get_special_ability(const std::string& ability) const { unit_ability_list abil_list = list_ability(ability); + for(unit_ability_list::iterator i = abil_list.begin(); i != abil_list.end();) { + if((*i->ability_cfg)["overwrite_specials"].to_bool()) { + return abil_list; + } + ++i; + } abil_list.append(get_specials(ability)); return abil_list; } diff --git a/wml_test_schedule b/wml_test_schedule index 362780d4819..ed709202928 100644 --- a/wml_test_schedule +++ b/wml_test_schedule @@ -167,6 +167,7 @@ 0 feeding 0 swarm_disables_upgrades 0 swarm_disables_upgrades_with_abilities +0 test_force_chance_to_hit_macro # # Deterministic unit facing tests 0 recruit_facing_enemy_one