Implement certain weapon specials in the engine
Support ['specials'] in abilities except plagues, heal_on_hit and swarm, which emulate the weapon specials with [affect_adjacent] in option and the possibility to affect all weapons filtered (used with 'Initiative' in HttH or 'Formation' in UtBS). (Don't put filter_weapon in 'filter_self/opponent' like in true weapons specials.) Closes #3630 Closes #3620
This commit is contained in:
parent
1f9a614dbc
commit
7f7217cf15
11 changed files with 237 additions and 276 deletions
|
@ -28,6 +28,10 @@
|
|||
* Support [filter_second_weapon] in leadership and resistance abilities,
|
||||
which activates the ability only when the affected unit's opponent
|
||||
is using a matching weapon.
|
||||
* Support ['specials'] in abilities except plagues, heal_on_hit and swarm , which emulate the weapon
|
||||
specials with [affect_adjacent] in option and the possibility to affect all weapons filtered(used with
|
||||
'Initiative' in httt or 'Formation' in utbs). (don't put filter_weapon in 'filter_self/opponent' like
|
||||
in true weapons specials).
|
||||
* Support WFL and percentages in [random_placement]num_items=
|
||||
* Support [or] in [filter_wml] and similar places
|
||||
* Support globbing in [filter_wml] via glob_on_* keys
|
||||
|
|
|
@ -95,7 +95,6 @@
|
|||
|
||||
{SOUND:HIT_AND_MISS {SOUND_LIST:SWORD_SWISH} {SOUND_LIST:MISS} -100}
|
||||
[/attack_anim]
|
||||
{WEAPON_SPECIAL_INITIATIVE_EVENTS}
|
||||
[variation]
|
||||
variation_id=sceptre
|
||||
hide_help=yes
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
|
||||
{SOUND:HIT_AND_MISS {SOUND_LIST:SWORD_SWISH} {SOUND_LIST:MISS} -75}
|
||||
[/attack_anim]
|
||||
{WEAPON_SPECIAL_INITIATIVE_EVENTS}
|
||||
[variation]
|
||||
variation_id=sceptre
|
||||
hide_help=yes
|
||||
|
|
|
@ -1,139 +1,18 @@
|
|||
#textdomain wesnoth-httt
|
||||
|
||||
# NOTE: This code is tailored for Li'sar in this campaign specifically, and will
|
||||
# not work correctly elsewhere without modification.
|
||||
|
||||
#define ABILITY_INITIATIVE
|
||||
[dummy]
|
||||
[firststrike]
|
||||
id=initiative
|
||||
name= _ "initiative"
|
||||
description= _ "All adjacent friendly units will strike first in melee combat, even when defending."
|
||||
[/dummy]
|
||||
affect_self=no
|
||||
[filter_second_weapon]
|
||||
range=melee
|
||||
[/filter_second_weapon]
|
||||
[affect_adjacent]
|
||||
[/affect_adjacent]
|
||||
[/firststrike]
|
||||
#enddef
|
||||
|
||||
#define SPECIAL_NOTES_INITIATIVE
|
||||
_" This unit's grasp of melee tactics allows adjacent allies to strike the first blow even when defending."#enddef
|
||||
|
||||
#define INITIATIVE_OBJECT FILTER
|
||||
[object]
|
||||
silent=yes
|
||||
|
||||
[filter]
|
||||
{FILTER}
|
||||
[/filter]
|
||||
|
||||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
|
||||
[set_specials]
|
||||
mode=append
|
||||
|
||||
[firststrike]
|
||||
id=initiative
|
||||
name=""
|
||||
description=""
|
||||
[filter_self]
|
||||
[filter_adjacent]
|
||||
id="Li'sar"
|
||||
[/filter_adjacent]
|
||||
[/filter_self]
|
||||
[/firststrike]
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[/object]
|
||||
#enddef
|
||||
|
||||
#define LACKS_INITIATIVE_FILTER
|
||||
side=1,2
|
||||
|
||||
[filter_side]
|
||||
[allied_with]
|
||||
[has_unit]
|
||||
id="Li'sar"
|
||||
[/has_unit]
|
||||
[/allied_with]
|
||||
[/filter_side]
|
||||
|
||||
[filter_wml]
|
||||
[attack]
|
||||
range=melee
|
||||
[/attack]
|
||||
[/filter_wml]
|
||||
|
||||
[not]
|
||||
[filter_wml]
|
||||
[attack]
|
||||
range=melee
|
||||
[specials]
|
||||
[firststrike]
|
||||
[/firststrike]
|
||||
[/specials]
|
||||
[/attack]
|
||||
[/filter_wml]
|
||||
[/not]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_INITIATIVE_EVENTS
|
||||
[event]
|
||||
id=initiative_1
|
||||
name=prerecruit,prerecall
|
||||
first_time_only=no
|
||||
|
||||
[filter]
|
||||
{LACKS_INITIATIVE_FILTER}
|
||||
[/filter]
|
||||
[allow_undo]
|
||||
[/allow_undo]
|
||||
[on_undo]
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=$unit.id
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
remove_specials=initiative
|
||||
[/effect]
|
||||
[/modify_unit]
|
||||
[/on_undo]
|
||||
|
||||
{INITIATIVE_OBJECT x,y=$x1,$y1}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
id=initiative_2
|
||||
name=side 1 turn, side 2 turn
|
||||
first_time_only=no
|
||||
|
||||
[store_unit]
|
||||
[filter]
|
||||
{LACKS_INITIATIVE_FILTER}
|
||||
[/filter]
|
||||
|
||||
kill=no
|
||||
variable=units_lacking_initiative
|
||||
[/store_unit]
|
||||
|
||||
[foreach]
|
||||
array=units_lacking_initiative
|
||||
[do]
|
||||
{INITIATIVE_OBJECT x,y=$this_item.x,$this_item.y}
|
||||
[/do]
|
||||
[/foreach]
|
||||
|
||||
{CLEAR_VARIABLE units_lacking_initiative}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
id=initiative_3
|
||||
name=attack
|
||||
first_time_only=no
|
||||
|
||||
[filter_second]
|
||||
{LACKS_INITIATIVE_FILTER}
|
||||
[/filter_second]
|
||||
|
||||
{INITIATIVE_OBJECT x,y=$x2,$y2}
|
||||
[/event]
|
||||
#enddef
|
||||
|
|
|
@ -170,7 +170,6 @@
|
|||
# Add global events
|
||||
[+campaign]
|
||||
{WEAPON_SPECIAL_DAZE_EVENTS}
|
||||
{ABILITY_FORMATION_EVENTS}
|
||||
{ABILITY_DISENGAGE_EVENTS}
|
||||
{ABILITY_SUPPORT_EVENTS}
|
||||
# On recruit, this switches the higher-recruit-cost units to the normal
|
||||
|
|
|
@ -94,13 +94,43 @@ _" This unit is capable of healing those around it, slowing dehydration, and cur
|
|||
[/attacks]
|
||||
#enddef
|
||||
|
||||
#define FORMATION ID GREATER_THAN COUNT
|
||||
[chance_to_hit]
|
||||
id={ID}
|
||||
apply_to=opponent
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to={GREATER_THAN}
|
||||
[/filter_base_value]
|
||||
[filter_self]
|
||||
[filter_adjacent]
|
||||
is_enemy=no
|
||||
count={COUNT}
|
||||
ability=formation
|
||||
[/filter_adjacent]
|
||||
[/filter_self]
|
||||
[/chance_to_hit]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_FORMATION
|
||||
[dummy]
|
||||
id=formation
|
||||
name= _ "formation"
|
||||
female_name= _ "female^formation"
|
||||
description= _ "This unit gains a +10% bonus to defense when another unit with the same ability is adjacent to it. However, this cannot raise the unit’s defense above 70%."
|
||||
[filter]
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=1-5
|
||||
[/filter_adjacent]
|
||||
[/filter]
|
||||
[/dummy]
|
||||
{FORMATION formation1 40 1-5}
|
||||
{FORMATION formation2 50 2-5}
|
||||
{FORMATION formation3 60 3-5}
|
||||
{FORMATION formation4 70 4-5}
|
||||
{FORMATION formation5 80 5}
|
||||
#enddef
|
||||
|
||||
#define ABILITY_DISENGAGE
|
||||
|
@ -531,139 +561,6 @@ _"This unit is capable of distracting opponents, allowing allied units to trespa
|
|||
[/event]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_FORMATION_EVENTS
|
||||
[event]
|
||||
id=ability_formation_event
|
||||
name=unit placed
|
||||
first_time_only=no
|
||||
|
||||
[filter]
|
||||
[not]
|
||||
side=1
|
||||
[/not]
|
||||
|
||||
[not]
|
||||
[filter_wml]
|
||||
[attack]
|
||||
[specials]
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_1
|
||||
[/chance_to_hit]
|
||||
[/specials]
|
||||
[/attack]
|
||||
[/filter_wml]
|
||||
[/not]
|
||||
[/filter]
|
||||
|
||||
[object]
|
||||
silent=yes
|
||||
|
||||
[filter]
|
||||
id=$unit.id
|
||||
[/filter]
|
||||
|
||||
[effect]
|
||||
apply_to=attack
|
||||
|
||||
[set_specials]
|
||||
mode=append
|
||||
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_1
|
||||
name=""
|
||||
description=""
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to=40
|
||||
[/filter_base_value]
|
||||
[filter_opponent]
|
||||
ability=formation
|
||||
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=1-5
|
||||
[/filter_adjacent]
|
||||
[/filter_opponent]
|
||||
[/chance_to_hit]
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_2
|
||||
name=""
|
||||
description=""
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to=50
|
||||
[/filter_base_value]
|
||||
[filter_opponent]
|
||||
ability=formation
|
||||
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=2-5
|
||||
[/filter_adjacent]
|
||||
[/filter_opponent]
|
||||
[/chance_to_hit]
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_3
|
||||
name=""
|
||||
description=""
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to=60
|
||||
[/filter_base_value]
|
||||
[filter_opponent]
|
||||
ability=formation
|
||||
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=3-5
|
||||
[/filter_adjacent]
|
||||
[/filter_opponent]
|
||||
[/chance_to_hit]
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_4
|
||||
name=""
|
||||
description=""
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to=70
|
||||
[/filter_base_value]
|
||||
[filter_opponent]
|
||||
ability=formation
|
||||
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=4-5
|
||||
[/filter_adjacent]
|
||||
[/filter_opponent]
|
||||
[/chance_to_hit]
|
||||
[chance_to_hit]
|
||||
id=formation_enemy_5
|
||||
name=""
|
||||
description=""
|
||||
sub=10
|
||||
[filter_base_value]
|
||||
greater_than_equal_to=80
|
||||
[/filter_base_value]
|
||||
[filter_opponent]
|
||||
ability=formation
|
||||
|
||||
[filter_adjacent]
|
||||
ability=formation
|
||||
is_enemy=no
|
||||
count=5
|
||||
[/filter_adjacent]
|
||||
[/filter_opponent]
|
||||
[/chance_to_hit]
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[/object]
|
||||
[/event]
|
||||
#enddef
|
||||
|
||||
#define ABILITY_SUPPORT_EVENTS
|
||||
[event]
|
||||
name=unit placed
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "units/abilities.hpp"
|
||||
#include "units/animation_component.hpp"
|
||||
#include "units/helper.hpp"
|
||||
#include "units/filter.hpp"
|
||||
#include "units/map.hpp"
|
||||
#include "units/udisplay.hpp"
|
||||
#include "units/unit.hpp"
|
||||
|
@ -135,13 +136,16 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
|
|||
opp_ctx.emplace(opp_weapon->specials_context(&opp, &u, opp_loc, u_loc, !attacking, weapon));
|
||||
}
|
||||
|
||||
slows = weapon->get_special_bool("slow");
|
||||
drains = !opp.get_state("undrainable") && weapon->get_special_bool("drains");
|
||||
petrifies = weapon->get_special_bool("petrifies");
|
||||
poisons = !opp.get_state("unpoisonable") && weapon->get_special_bool("poison") && !opp.get_state(unit::STATE_POISONED);
|
||||
slows = weapon->bool_ability("slow");
|
||||
drains = !opp.get_state("undrainable") && weapon->bool_ability("drains");
|
||||
petrifies = weapon->bool_ability("petrifies");
|
||||
poisons = !opp.get_state("unpoisonable") && weapon->bool_ability("poison") && !opp.get_state(unit::STATE_POISONED);
|
||||
backstab_pos = is_attacker && backstab_check(u_loc, opp_loc, units, resources::gameboard->teams());
|
||||
rounds = weapon->get_specials("berserk").highest("value", 1).first;
|
||||
firststrike = weapon->get_special_bool("firststrike");
|
||||
if(weapon->combat_ability("berserk", 1).second) {
|
||||
rounds = weapon->combat_ability("berserk", 1).first;
|
||||
}
|
||||
firststrike = weapon->bool_ability("firststrike");
|
||||
|
||||
{
|
||||
const int distance = distance_between(u_loc, opp_loc);
|
||||
|
@ -172,6 +176,10 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
|
|||
unit_abilities::effect cth_effects(cth_specials, cth, backstab_pos);
|
||||
cth = cth_effects.get_composite_value();
|
||||
|
||||
cth = utils::clamp(cth, 0, 100);
|
||||
|
||||
cth = weapon->combat_ability("chance_to_hit", cth, backstab_pos).first;
|
||||
|
||||
if(opp.get_state("invulnerable")) {
|
||||
cth = 0;
|
||||
}
|
||||
|
@ -207,11 +215,15 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
|
|||
|
||||
// Compute drain amounts only if draining is possible.
|
||||
if(drains) {
|
||||
unit_ability_list drain_specials = weapon->get_specials("drains");
|
||||
|
||||
// Compute the drain percent (with 50% as the base for backward compatibility)
|
||||
unit_abilities::effect drain_percent_effects(drain_specials, 50, backstab_pos);
|
||||
drain_percent = drain_percent_effects.get_composite_value();
|
||||
if (weapon->get_special_bool("drains")) {
|
||||
unit_ability_list drain_specials = weapon->get_specials("drains");
|
||||
// Compute the drain percent (with 50% as the base for backward compatibility)
|
||||
unit_abilities::effect drain_percent_effects(drain_specials, 50, backstab_pos);
|
||||
drain_percent = drain_percent_effects.get_composite_value();
|
||||
}
|
||||
if (weapon->combat_ability("drains", 50, backstab_pos).second) {
|
||||
drain_percent = weapon->combat_ability("drains", 50, backstab_pos).first;
|
||||
}
|
||||
}
|
||||
|
||||
// Add heal_on_hit (the drain constant)
|
||||
|
@ -1563,6 +1575,159 @@ std::pair<int, map_location> under_leadership(const unit_map& units, const map_l
|
|||
return abil.highest("value");
|
||||
}
|
||||
|
||||
//begin of weapon emulates function.
|
||||
|
||||
bool unit::abilities_filter_matches(const config& cfg, bool attacker, int res) const
|
||||
{
|
||||
if(!(cfg["active_on"].empty() || (attacker && cfg["active_on"] == "offense") || (!attacker && cfg["active_on"] == "defense"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!unit_abilities::filter_base_matches(cfg, res)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//functions for emulate weapon specials.
|
||||
//filter opponent and affect self/opponent/both option.
|
||||
bool unit::ability_filter_opponent(const std::string& ability,const config& cfg,const map_location& loc) const
|
||||
{
|
||||
const config &filter = cfg.child("filter_opponent");
|
||||
if(!filter) {
|
||||
return true;
|
||||
}
|
||||
return unit_filter(vconfig(filter)).set_use_flat_tod(ability == "illuminates").matches(*this, loc);
|
||||
}
|
||||
|
||||
bool leadership_affects_self(const std::string& ability,const unit_map& units, const map_location& loc, const_attack_ptr weapon,const_attack_ptr opp_weapon)
|
||||
{
|
||||
const unit_map::const_iterator un = units.find(loc);
|
||||
if(un == units.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unit_ability_list abil = un->get_abilities(ability, weapon, opp_weapon);
|
||||
for(unit_ability_list::iterator i = abil.begin(); i != abil.end();) {
|
||||
const std::string& apply_to = (*i->first)["apply_to"];
|
||||
if(apply_to.empty()||apply_to == "both"||apply_to == "under") {
|
||||
return true;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool leadership_affects_opponent(const std::string& ability,const unit_map& units, const map_location& loc, const_attack_ptr weapon,const_attack_ptr opp_weapon)
|
||||
{
|
||||
const unit_map::const_iterator un = units.find(loc);
|
||||
if(un == units.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unit_ability_list abil = un->get_abilities(ability, weapon, opp_weapon);
|
||||
for(unit_ability_list::iterator i = abil.begin(); i != abil.end();) {
|
||||
const std::string& apply_to = (*i->first)["apply_to"];
|
||||
if(apply_to == "both"||apply_to == "opponent") {
|
||||
return true;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//sub function for emulate chance_to_hit,damage drains and attacks special.
|
||||
std::pair<int, bool> ability_leadership(const std::string& ability,const unit_map& units, const map_location& loc, const map_location& opp_loc, bool attacker, int abil_value, bool backstab_pos, const_attack_ptr weapon, const_attack_ptr opp_weapon)
|
||||
{
|
||||
const unit_map::const_iterator un = units.find(loc);
|
||||
const unit_map::const_iterator up = units.find(opp_loc);
|
||||
if(un == units.end()) {
|
||||
return {abil_value, false};
|
||||
}
|
||||
|
||||
unit_ability_list abil = un->get_abilities(ability, weapon, opp_weapon);
|
||||
for(unit_ability_list::iterator i = abil.begin(); i != abil.end();) {
|
||||
const config &filter = (*i->first).child("filter_opponent");
|
||||
bool show_result = false;
|
||||
if(up == units.end() && !filter) {
|
||||
show_result = un->abilities_filter_matches(*i->first, attacker, abil_value);
|
||||
} else if(up == units.end() && filter) {
|
||||
return {abil_value, false};
|
||||
} else {
|
||||
show_result = !(!un->abilities_filter_matches(*i->first, attacker, abil_value) || !up->ability_filter_opponent(ability, *i->first, opp_loc));
|
||||
}
|
||||
|
||||
if(!show_result) {
|
||||
i = abil.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if(!abil.empty()) {
|
||||
unit_abilities::effect leader_effect(abil, abil_value, backstab_pos);
|
||||
return {leader_effect.get_composite_value(), true};
|
||||
}
|
||||
return {abil_value, false};
|
||||
}
|
||||
|
||||
//sub function for wmulate boolean special(slow, poison...)
|
||||
bool bool_leadership(const std::string& ability,const unit_map& units, const map_location& loc, const map_location& opp_loc, bool attacker, const_attack_ptr weapon, const_attack_ptr opp_weapon)
|
||||
{
|
||||
const unit_map::const_iterator un = units.find(loc);
|
||||
const unit_map::const_iterator up = units.find(opp_loc);
|
||||
if(un == units.end() || up == units.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unit_ability_list abil = un->get_abilities(ability, weapon, opp_weapon);
|
||||
for(unit_ability_list::iterator i = abil.begin(); i != abil.end();) {
|
||||
const std::string& active_on = (*i->first)["active_on"];
|
||||
if(!(active_on.empty() || (attacker && active_on == "offense") || (!attacker && active_on == "defense")) || !up->ability_filter_opponent(ability, *i->first, opp_loc)) {
|
||||
i = abil.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if(!abil.empty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//emulate boolean special for self/adjacent and/or opponent.
|
||||
bool attack_type::bool_ability(const std::string& ability) const
|
||||
{
|
||||
bool abil_bool= get_special_bool(ability);
|
||||
const unit_map& units = display::get_singleton()->get_units();
|
||||
|
||||
if(leadership_affects_self(ability, units, self_loc_, shared_from_this(), other_attack_)) {
|
||||
abil_bool = bool_leadership(ability, units, self_loc_, other_loc_, is_attacker_, shared_from_this(), other_attack_);
|
||||
}
|
||||
|
||||
if(leadership_affects_opponent(ability, units, other_loc_, other_attack_, shared_from_this())) {
|
||||
abil_bool = bool_leadership(ability, units, other_loc_, self_loc_, !is_attacker_, other_attack_, shared_from_this());
|
||||
}
|
||||
return abil_bool;
|
||||
}
|
||||
|
||||
//emulate numerical special for self/adjacent and/or opponent.
|
||||
std::pair<int, bool> attack_type::combat_ability(const std::string& ability, int abil_value, bool backstab_pos) const
|
||||
{
|
||||
const unit_map& units = display::get_singleton()->get_units();
|
||||
|
||||
if(leadership_affects_self(ability, units, self_loc_, shared_from_this(), other_attack_)) {
|
||||
return ability_leadership(ability, units, self_loc_, other_loc_, is_attacker_, abil_value, backstab_pos, shared_from_this(), other_attack_);
|
||||
}
|
||||
|
||||
if(leadership_affects_opponent(ability, units, other_loc_, other_attack_, shared_from_this())) {
|
||||
return ability_leadership(ability, units, other_loc_,self_loc_, !is_attacker_, abil_value, backstab_pos, other_attack_, shared_from_this());
|
||||
}
|
||||
return {abil_value, false};
|
||||
}
|
||||
//end of emulate weapon special functions.
|
||||
|
||||
int combat_modifier(const unit_map& units,
|
||||
const gamemap& map,
|
||||
const map_location& loc,
|
||||
|
|
|
@ -279,6 +279,10 @@ void attack_unit_and_advance(const map_location& attacker,
|
|||
* or 0 and map_location::null_location() otherwise.
|
||||
*/
|
||||
std::pair<int, map_location> under_leadership(const unit_map& units, const map_location& loc, const_attack_ptr weapon, const_attack_ptr opp_weapon = nullptr);
|
||||
bool leadership_affects_self(const std::string& ability,const unit_map& units, const map_location& loc, const_attack_ptr weapon=nullptr,const_attack_ptr opp_weapon=nullptr);
|
||||
bool leadership_affects_opponent(const std::string& ability,const unit_map& units, const map_location& loc, const_attack_ptr weapon=nullptr,const_attack_ptr opp_weapon=nullptr);
|
||||
std::pair<int, bool> ability_leadership(const std::string& ability, const unit_map& units, const map_location& loc, const map_location& opp_loc, bool attacker=true, int abil_value=0, bool backstab_pos=false, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr);
|
||||
bool bool_leadership(const std::string& ability,const unit_map& units, const map_location& loc, const map_location& opp_loc, bool attacker=true, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr);
|
||||
|
||||
/**
|
||||
* Returns the amount that a unit's damage should be multiplied by
|
||||
|
|
|
@ -824,6 +824,10 @@ void attack_type::modified_attacks(bool is_backstab, unsigned & min_attacks,
|
|||
unit_abilities::effect attacks_effect(get_specials("attacks"),
|
||||
num_attacks(), is_backstab);
|
||||
int attacks_value = attacks_effect.get_composite_value();
|
||||
if ( combat_ability("attacks", attacks_value, is_backstab).second ) {
|
||||
attacks_value = combat_ability("attacks", attacks_value, is_backstab).first;
|
||||
}
|
||||
|
||||
if ( attacks_value < 0 ) {
|
||||
attacks_value = num_attacks();
|
||||
ERR_NG << "negative number of strikes after applying weapon specials" << std::endl;
|
||||
|
@ -846,7 +850,11 @@ void attack_type::modified_attacks(bool is_backstab, unsigned & min_attacks,
|
|||
int attack_type::modified_damage(bool is_backstab) const
|
||||
{
|
||||
unit_abilities::effect dmg_effect(get_specials("damage"), damage(), is_backstab);
|
||||
return dmg_effect.get_composite_value();
|
||||
int damage_value = dmg_effect.get_composite_value();
|
||||
if ( combat_ability("damage", damage_value, is_backstab).second ) {
|
||||
damage_value = combat_ability("damage", damage_value, is_backstab).first;
|
||||
}
|
||||
return damage_value;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@ public:
|
|||
void set_defense_weight(double value) { defense_weight_ = value; }
|
||||
void set_specials(config value) { specials_ = value; }
|
||||
|
||||
// In action/attack.cpp
|
||||
std::pair<int, bool> combat_ability(const std::string& ability, int abil_value = 0, bool backstab_pos = false) const;
|
||||
bool bool_ability(const std::string& ability) const;
|
||||
|
||||
|
||||
// In unit_abilities.cpp:
|
||||
|
||||
|
|
|
@ -1537,6 +1537,9 @@ public:
|
|||
*/
|
||||
void remove_ability_by_id(const std::string& ability);
|
||||
|
||||
bool abilities_filter_matches(const config& cfg, bool attacker, int res) const;
|
||||
bool ability_filter_opponent(const std::string& ability,const config& cfg,const map_location& loc) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Check if an ability is active.
|
||||
|
|
Loading…
Add table
Reference in a new issue