add a 'replacement_type' and 'alternative_type' attribute in [damage] special or ability who modify the type of attack used (#7865)
At the suggestion of @stevecotton, I propose a special 'replacement_type' and 'alternative_type' attribute capable of modifying the type of attack used when the conditions are met. Also make Holy water combine arcane damage with native type of weapon Like holy water imbued ordinary weapon, it's seem logic what arcane damage dominant what if more efficient what original type(water can't altered pierce or blading of spear or sword)
This commit is contained in:
parent
ae4242a430
commit
3910817cf7
30 changed files with 516 additions and 35 deletions
2
changelog_entries/[damage]_special_changelog.md
Normal file
2
changelog_entries/[damage]_special_changelog.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
### WML Engine
|
||||
* Add a 'replacement_type' and 'alternative_type' attribute to [damage] to change the type of attack under specific conditions (terrain, time of day, leadership etc...)
|
|
@ -261,7 +261,10 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=overlay
|
||||
|
|
|
@ -146,9 +146,9 @@
|
|||
[/gold_carryover]
|
||||
[/objectives]
|
||||
|
||||
{OBJ_POTION_HOLY 16 5 shadows_holywater1}
|
||||
{OBJ_POTION_HOLY 32 5 shadows_holywater2}
|
||||
{OBJ_POTION_HOLY 20 10 shadows_holywater3}
|
||||
{OBJ_POTION_HOLY_ALT 16 5 shadows_holywater1}
|
||||
{OBJ_POTION_HOLY_ALT 32 5 shadows_holywater2}
|
||||
{OBJ_POTION_HOLY_ALT 20 10 shadows_holywater3}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
|
|
|
@ -201,9 +201,9 @@
|
|||
[/note]
|
||||
[/objectives]
|
||||
|
||||
{OBJ_POTION_HOLY 26 19 showdown_holywater1}
|
||||
{OBJ_POTION_HOLY 30 20 showdown_holywater2}
|
||||
{OBJ_POTION_HOLY 29 20 showdown_holywater3}
|
||||
{OBJ_POTION_HOLY_ALT 26 19 showdown_holywater1}
|
||||
{OBJ_POTION_HOLY_ALT 30 20 showdown_holywater2}
|
||||
{OBJ_POTION_HOLY_ALT 29 20 showdown_holywater3}
|
||||
|
||||
[remove_shroud]
|
||||
side=1,2
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
{TURNS_RUN_OUT}
|
||||
{IS_LAST_SCENARIO}
|
||||
[/objectives]
|
||||
{OBJ_POTION_HOLY 23 3 object7_holywater}
|
||||
{OBJ_POTION_HOLY_ALT 23 3 object7_holywater}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
|
|
|
@ -142,7 +142,10 @@ crystal_quiver #enddef
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=ranged
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
name=bow,crossbow,composite bow
|
||||
[/effect]
|
||||
[effect]
|
||||
|
@ -196,7 +199,10 @@ holy_amulet_3 #enddef
|
|||
(
|
||||
[effect]
|
||||
apply_to=attack
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=overlay
|
||||
|
|
|
@ -313,7 +313,10 @@
|
|||
set_name=holy sword
|
||||
set_description=_ "holy sword"
|
||||
set_icon=attacks/sword-holy.png
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
increase_damage=1
|
||||
increase_attacks=2
|
||||
[/effect]
|
||||
|
|
|
@ -190,8 +190,8 @@
|
|||
|
||||
{STARTING_VILLAGES 4 6}
|
||||
|
||||
{OBJ_POTION_HOLY 5 23 object7_holywater}
|
||||
{OBJ_POTION_HOLY 31 43 object7_holywater2}
|
||||
{OBJ_POTION_HOLY_ALT 5 23 object7_holywater}
|
||||
{OBJ_POTION_HOLY_ALT 31 43 object7_holywater2}
|
||||
|
||||
[event]
|
||||
name=prestart
|
||||
|
@ -270,7 +270,10 @@
|
|||
set_name=holy sword
|
||||
set_description=_ "holy sword"
|
||||
set_icon=attacks/sword-holy.png
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
increase_damage=1
|
||||
increase_attacks=2
|
||||
[/effect]
|
||||
|
|
|
@ -285,11 +285,11 @@
|
|||
{PLACE_IMAGE items/bonestack.png 34 6}
|
||||
|
||||
# Place holy water - uses core macro to set up required pickup event as well
|
||||
{OBJ_POTION_HOLY 34 26 object7_holywater}
|
||||
{OBJ_POTION_HOLY 33 27 object7_holywater2}
|
||||
{OBJ_POTION_HOLY 33 28 object7_holywater3}
|
||||
{OBJ_POTION_HOLY 32 26 object7_holywater4}
|
||||
{OBJ_POTION_HOLY 32 27 object7_holywater5}
|
||||
{OBJ_POTION_HOLY_ALT 34 26 object7_holywater}
|
||||
{OBJ_POTION_HOLY_ALT 33 27 object7_holywater2}
|
||||
{OBJ_POTION_HOLY_ALT 33 28 object7_holywater3}
|
||||
{OBJ_POTION_HOLY_ALT 32 26 object7_holywater4}
|
||||
{OBJ_POTION_HOLY_ALT 32 27 object7_holywater5}
|
||||
|
||||
[event]
|
||||
name=prestart
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
{PLACE_IMAGE (items/dragonstatue.png) 12 1}
|
||||
{PLACE_IMAGE "items/dragonstatue.png~FL(horiz)" 14 1}
|
||||
|
||||
{OBJ_POTION_HOLY 13 19 (holy_helper)}
|
||||
{OBJ_POTION_HOLY_ALT 13 19 (holy_helper)}
|
||||
|
||||
[recall]
|
||||
id=Burin the Lost
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
{PLACE_IMAGE (scenery/temple1.png) 10 17}
|
||||
{PLACE_IMAGE (scenery/temple1.png) 9 15}
|
||||
|
||||
{OBJ_POTION_HOLY 29 24 (holy_water1)}
|
||||
{OBJ_POTION_HOLY_ALT 29 24 (holy_water1)}
|
||||
|
||||
[set_variable]
|
||||
name=queen_awake
|
||||
|
@ -276,7 +276,7 @@
|
|||
{CLEAR_VARIABLE random}
|
||||
|
||||
#ifdef EASY
|
||||
{OBJ_POTION_HOLY 28 26 (holy_water2)}
|
||||
{OBJ_POTION_HOLY_ALT 28 26 (holy_water2)}
|
||||
#endif
|
||||
|
||||
[objectives]
|
||||
|
|
|
@ -1553,7 +1553,10 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[/object]
|
||||
|
||||
|
|
|
@ -743,10 +743,13 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
# Exclude arcane attacks in case Garak picked up the holy
|
||||
# the type=arcane or alternative_type=arcane must be filtered in case Garak picked up the holy
|
||||
# water in the second scenario - in that case he gets to keep it
|
||||
[not]
|
||||
type=arcane
|
||||
[or]
|
||||
alternative_type=arcane
|
||||
[/or]
|
||||
[/not]
|
||||
set_type=fire
|
||||
[/effect]
|
||||
|
|
|
@ -314,7 +314,10 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
increase_damage=25%
|
||||
[/effect]
|
||||
[effect]
|
||||
|
|
|
@ -769,7 +769,10 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range={WC_STR_ID_{RANGE}}
|
||||
set_type=arcane
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
increase_damage=25%
|
||||
[/effect]
|
||||
[/chance]
|
||||
|
|
|
@ -267,7 +267,7 @@
|
|||
[/event]
|
||||
#enddef
|
||||
|
||||
#define OBJ_POTION_HOLY X Y ID
|
||||
#define OBJ_POTION_HOLY_COMMON X Y ID ARCANE
|
||||
# Places holy water that turns the unit's melee attacks into arcane attacks. It can only be used once.
|
||||
{PICKUPPABLE_ITEM {ID} {X} {Y} (
|
||||
side=1
|
||||
|
@ -290,7 +290,7 @@
|
|||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_type=arcane
|
||||
{ARCANE}
|
||||
[/effect]
|
||||
[/object]
|
||||
[sound]
|
||||
|
@ -299,6 +299,21 @@
|
|||
)}
|
||||
#enddef
|
||||
|
||||
#define OBJ_POTION_HOLY X Y ID
|
||||
{OBJ_POTION_HOLY_COMMON {X} {Y} {ID} (set_type=arcane)}
|
||||
#enddef
|
||||
|
||||
#define SET_WEAPON_ARCANE
|
||||
[set_specials]
|
||||
mode=append
|
||||
{WEAPON_SPECIAL_ARCANE}
|
||||
[/set_specials]
|
||||
#enddef
|
||||
|
||||
#define OBJ_POTION_HOLY_ALT X Y ID
|
||||
{OBJ_POTION_HOLY_COMMON {X} {Y} {ID} {SET_WEAPON_ARCANE}}
|
||||
#enddef
|
||||
|
||||
#define OBJ_POTION_STRONG X Y ID
|
||||
# Places a potion of strength that increases the unit's damage by 1 per strike on melee attacks. It can only be used once.
|
||||
[item]
|
||||
|
|
|
@ -201,3 +201,13 @@
|
|||
special_note=_ "This unit is able to stun its enemies, disrupting their zones of control."
|
||||
[/stun]
|
||||
#enddef
|
||||
|
||||
#define WEAPON_SPECIAL_ARCANE
|
||||
[damage]
|
||||
id=arcane_damage
|
||||
name= _ "arcane"
|
||||
description= _ "This attack combines the arcane type with the type of weapon used so that resistance to the arcane type does not penalize the user."
|
||||
special_note=_ "This unit can use the arcane type when the opponent is particularly sensitive to it in relation to the weapon on which it is applied."
|
||||
alternative_type=arcane
|
||||
[/damage]
|
||||
#enddef
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
{SIMPLE_KEY range string_list}
|
||||
{SIMPLE_KEY name string_list}
|
||||
{SIMPLE_KEY type string_list}
|
||||
{SIMPLE_KEY replacement_type string_list}
|
||||
{SIMPLE_KEY alternative_type string_list}
|
||||
{SIMPLE_KEY special string_list}
|
||||
{SIMPLE_KEY special_active string_list}
|
||||
{SIMPLE_KEY special_id string_list}
|
||||
|
|
|
@ -75,6 +75,8 @@
|
|||
name="damage"
|
||||
max=infinite
|
||||
super="units/unit_type/attack/specials/~value~"
|
||||
{SIMPLE_KEY replacement_type string}
|
||||
{SIMPLE_KEY alternative_type string}
|
||||
[/tag]
|
||||
[tag]
|
||||
name="drains"
|
||||
|
|
|
@ -2745,7 +2745,7 @@ For game purposes, the races group into factions; for example, orcs often cooper
|
|||
{OBJ_RING_SLOW 11 4 OBJ2}
|
||||
{OBJ_POTION_HEALING 12 4 OBJ3}
|
||||
{OBJ_POTION_POISON 13 5 OBJ4}
|
||||
{OBJ_POTION_HOLY 14 4 OBJ5}
|
||||
{OBJ_POTION_HOLY_ALT 14 4 OBJ5}
|
||||
{OBJ_POTION_STRONG 15 4 OBJ6}
|
||||
{OBJ_POTION_DECAY 11 5 OBJ7}
|
||||
{OBJ_TRIDENT_STORM 12 5 OBJ8}
|
||||
|
|
|
@ -0,0 +1,316 @@
|
|||
#textdomain wesnoth-test
|
||||
|
||||
#####
|
||||
# API(s) being tested: [damage]replacement_type=
|
||||
##
|
||||
# Actions:
|
||||
# Give both Alice and Bob 100% chance to hit.
|
||||
# Give Bob one [damage] with replacement_type=fire and two [damage] with replacement_type=cold
|
||||
# change resistance of Bob to arcane to 50% and fire to -100%.
|
||||
# Give Alice one [damage] with replacement_type=cold, two [damage] with replacement_type=arcane and three with replacement_type=fire
|
||||
# and change Alice resistance to cold to -100% and fire to 50%.
|
||||
# Move Alice next to Bob, and have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# Alice attack with fire and Bob use cold.
|
||||
#####
|
||||
{GENERIC_UNIT_TEST "damage_type_test" (
|
||||
[event]
|
||||
name=start
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
max_hitpoints=100
|
||||
hitpoints=100
|
||||
attacks_left=1
|
||||
[/modify_unit]
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=resistance
|
||||
replace=yes
|
||||
[resistance]
|
||||
arcane=50
|
||||
fire=200
|
||||
[/resistance]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
[set_specials]
|
||||
mode=append
|
||||
[attacks]
|
||||
value=1
|
||||
[/attacks]
|
||||
[damage]
|
||||
value=12
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=fire
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=cold
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=cold
|
||||
[/damage]
|
||||
[chance_to_hit]
|
||||
value=100
|
||||
[/chance_to_hit]
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[filter]
|
||||
id=bob
|
||||
[/filter]
|
||||
[/object]
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=resistance
|
||||
replace=yes
|
||||
[resistance]
|
||||
cold=200
|
||||
fire=50
|
||||
[/resistance]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
[set_specials]
|
||||
mode=append
|
||||
[attacks]
|
||||
value=1
|
||||
[/attacks]
|
||||
[damage]
|
||||
value=12
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=cold
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=arcane
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=arcane
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=fire
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=fire
|
||||
[/damage]
|
||||
[damage]
|
||||
replacement_type=fire
|
||||
[/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]
|
||||
#damage without modification are 12, if test fail hitpoints !=76
|
||||
#if succed then damage by alice 24(bob vulnerable to fire and fire prioritized)
|
||||
#if succed then damage by bob 24(alice vulnerable to cold, cold priority is 1)
|
||||
{ASSERT ({VARIABLE_CONDITIONAL a.hitpoints equals 76})}
|
||||
{ASSERT ({VARIABLE_CONDITIONAL b.hitpoints equals 76})}
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
)}
|
||||
|
||||
#####
|
||||
# API(s) being tested: [damage]alternative_type=
|
||||
##
|
||||
# Actions:
|
||||
# Give both Alice and Bob 100% chance to hit.
|
||||
# Give Bob one [damage] with alternative_type=cold
|
||||
# change resistance Bob to blade to -100% and fire to 0%.
|
||||
# Give Alice one [damage] with alternative_type=fire
|
||||
# and change resistance to cold to -100% and blade to 0%.
|
||||
# Move Alice next to Bob, and have Alice attack Bob.
|
||||
##
|
||||
# Expected end state:
|
||||
# Alice attack with blade and Bob use cold.
|
||||
#####
|
||||
{GENERIC_UNIT_TEST "damage_secondary_type_test" (
|
||||
[event]
|
||||
name=start
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
max_hitpoints=100
|
||||
hitpoints=100
|
||||
attacks_left=1
|
||||
[/modify_unit]
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=resistance
|
||||
replace=yes
|
||||
[resistance]
|
||||
blade=200
|
||||
fire=100
|
||||
[/resistance]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
[set_specials]
|
||||
mode=append
|
||||
[attacks]
|
||||
value=1
|
||||
[/attacks]
|
||||
[damage]
|
||||
value=12
|
||||
[/damage]
|
||||
[damage]
|
||||
alternative_type=cold
|
||||
[/damage]
|
||||
[chance_to_hit]
|
||||
value=100
|
||||
[/chance_to_hit]
|
||||
[/set_specials]
|
||||
[/effect]
|
||||
[filter]
|
||||
id=bob
|
||||
[/filter]
|
||||
[/object]
|
||||
[object]
|
||||
silent=yes
|
||||
[effect]
|
||||
apply_to=resistance
|
||||
replace=yes
|
||||
[resistance]
|
||||
cold=200
|
||||
blade=100
|
||||
[/resistance]
|
||||
[/effect]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
[set_specials]
|
||||
mode=append
|
||||
[attacks]
|
||||
value=1
|
||||
[/attacks]
|
||||
[damage]
|
||||
value=12
|
||||
[/damage]
|
||||
[damage]
|
||||
alternative_type=fire
|
||||
[/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]
|
||||
#damage without modification are 12, if test fail hitpoints !=76
|
||||
#if succed then damage by alice 24(bob more vulnerable to blade)
|
||||
#if succed then damage by bob 24(alice vulnerable to cold, cold [damage] is used)
|
||||
{ASSERT ({VARIABLE_CONDITIONAL a.hitpoints equals 76})}
|
||||
{ASSERT ({VARIABLE_CONDITIONAL b.hitpoints equals 76})}
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
)}
|
|
@ -203,7 +203,12 @@ void attack_predictions::set_data(window& window, const combatant_data& attacker
|
|||
}
|
||||
}
|
||||
|
||||
ss << string_table["type_" + weapon->type()];
|
||||
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;
|
||||
|
||||
set_label_helper("resis_label", ss.str());
|
||||
|
||||
|
|
|
@ -115,6 +115,25 @@ void unit_attack::pre_show(window& window)
|
|||
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();
|
||||
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();
|
||||
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 = {"disable", "berserk", "drains", "heal_on_hit", "plague", "slow", "petrifies", "firststrike", "poison"};
|
||||
std::string attw_specials = attacker_weapon.weapon_specials();
|
||||
std::string attw_specials_dmg = attacker_weapon.weapon_specials_value({"leadership", "damage"});
|
||||
|
@ -163,22 +182,26 @@ void unit_attack::pre_show(window& window)
|
|||
|
||||
// Use attacker/defender.num_blows instead of attacker/defender_weapon.num_attacks() because the latter does not consider the swarm weapon special
|
||||
attacker_stats << "<b>" << attw_name << "</b>" << "\n"
|
||||
<< attw_type << attw_type_second << "\n"
|
||||
<< attacker.damage << font::weapon_numbers_sep << attacker.num_blows
|
||||
<< attw_specials << "\n"
|
||||
<< font::span_color(a_cth_color) << attacker.chance_to_hit << "%</span>";
|
||||
|
||||
attacker_tooltip << _("Weapon: ") << "<b>" << attw_name << "</b>" << "\n"
|
||||
<< _("Type: ") << attw_type << attw_type_second << "\n"
|
||||
<< _("Damage: ") << attacker.damage << "<i>" << attw_specials_dmg << "</i>" << "\n"
|
||||
<< _("Attacks: ") << attacker.num_blows << "<i>" << attw_specials_atk << "</i>" << "\n"
|
||||
<< _("Chance to hit: ") << font::span_color(a_cth_color) << attacker.chance_to_hit << "%</span>"<< "<i>" << attw_specials_cth << "</i>"
|
||||
<< attw_specials_others;
|
||||
|
||||
defender_stats << "<b>" << defw_name << "</b>" << "\n"
|
||||
<< defw_type << defw_type_second << "\n"
|
||||
<< defender.damage << font::weapon_numbers_sep << defender.num_blows
|
||||
<< defw_specials << "\n"
|
||||
<< font::span_color(d_cth_color) << defender.chance_to_hit << "%</span>";
|
||||
|
||||
defender_tooltip << _("Weapon: ") << "<b>" << defw_name << "</b>" << "\n"
|
||||
<< _("Type: ") << defw_type << defw_type_second << "\n"
|
||||
<< _("Damage: ") << defender.damage << "<i>" << defw_specials_dmg << "</i>" << "\n"
|
||||
<< _("Attacks: ") << defender.num_blows << "<i>" << defw_specials_atk << "</i>" << "\n"
|
||||
<< _("Chance to hit: ") << font::span_color(d_cth_color) << defender.chance_to_hit << "%</span>"<< "<i>" << defw_specials_cth << "</i>"
|
||||
|
|
|
@ -743,7 +743,12 @@ utils::string_map_res movetype::resistances::damage_table() const
|
|||
*/
|
||||
int movetype::resistances::resistance_against(const attack_type & attack) const
|
||||
{
|
||||
return cfg_[attack.type()].to_int(100);
|
||||
std::pair<std::string, std::string> types = attack.damage_type();
|
||||
int res = resistance_against(types.first);
|
||||
if(!(types.second).empty()){
|
||||
res = std::max(res, resistance_against(types.second));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -876,15 +876,22 @@ 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 lang_type = string_table["type_" + at.type()];
|
||||
std::pair<std::string, std::string> types = at.damage_type();
|
||||
std::string secondary_lang_type = types.second;
|
||||
if (!secondary_lang_type.empty()) {
|
||||
secondary_lang_type = ", " + string_table["type_" + secondary_lang_type];
|
||||
}
|
||||
std::string lang_type = string_table["type_" + types.first] + secondary_lang_type;
|
||||
|
||||
// SCALE_INTO() is needed in case the 72x72 images/misc/missing-image.png is substituted.
|
||||
const std::string range_png = std::string("icons/profiles/") + at.range() + "_attack.png~SCALE_INTO(16,16)";
|
||||
const std::string type_png = std::string("icons/profiles/") + at.type() + ".png~SCALE_INTO(16,16)";
|
||||
const std::string type_png = std::string("icons/profiles/") + types.first + ".png~SCALE_INTO(16,16)";
|
||||
const std::string secondary_type_png = !(types.second).empty() ? std::string("icons/profiles/") + types.second + ".png~SCALE_INTO(16,16)" : "";
|
||||
const bool range_png_exists = image::locator(range_png).file_exists();
|
||||
const bool type_png_exists = image::locator(type_png).file_exists();
|
||||
const bool secondary_type_png_exists = image::locator(secondary_type_png).file_exists();
|
||||
|
||||
if(!range_png_exists || !type_png_exists) {
|
||||
if(!range_png_exists || !type_png_exists || (!secondary_type_png_exists && !secondary_lang_type.empty())) {
|
||||
str << span_color(font::weapon_details_color) << " " << " "
|
||||
<< range << font::weapon_details_sep
|
||||
<< lang_type << "</span>\n";
|
||||
|
@ -941,6 +948,9 @@ static int attack_info(const reports::context& rc, const attack_type &at, config
|
|||
const std::string spacer = "misc/blank.png~CROP(0, 0, 16, 21)"; // 21 == 16+5
|
||||
add_image(res, spacer + "~BLIT(" + range_png + ",0,5)", damage_versus.tooltip);
|
||||
add_image(res, spacer + "~BLIT(" + type_png + ",0,5)", damage_versus.tooltip);
|
||||
if(secondary_type_png_exists){
|
||||
add_image(res, spacer + "~BLIT(" + secondary_type_png + ",0,5)", damage_versus.tooltip);
|
||||
}
|
||||
add_text(res, damage_and_num_attacks.str, damage_and_num_attacks.tooltip);
|
||||
add_text(res, damage_versus.str, damage_versus.tooltip); // This string is usually empty
|
||||
|
||||
|
|
|
@ -1168,6 +1168,48 @@ void attack_type::modified_attacks(unsigned & min_attacks,
|
|||
}
|
||||
}
|
||||
|
||||
//Functions used for change damage_type list with damage
|
||||
static std::vector<std::string> damage_type_list(const unit_ability_list& abil_list, const std::string& type)
|
||||
{
|
||||
std::vector<std::string> type_list;
|
||||
for(auto& i : abil_list) {
|
||||
if(!(*i.ability_cfg)[type].str().empty()){
|
||||
type_list.push_back((*i.ability_cfg)[type].str());
|
||||
}
|
||||
}
|
||||
if(type_list.size() >= 2){
|
||||
std::sort(type_list.begin(), type_list.end());
|
||||
if(type_list.size() >= 3){
|
||||
std::unordered_map<std::string, unsigned int> type_count;
|
||||
for( const std::string& character : type_list ){
|
||||
type_count[character]++;
|
||||
}
|
||||
std::sort( std::begin( type_list ) , std::end( type_list ) , [&]( const std::string& rhs , const std::string& lhs ){
|
||||
return type_count[lhs] < type_count[rhs];
|
||||
});
|
||||
}
|
||||
}
|
||||
return type_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of damage inflicted.
|
||||
*/
|
||||
std::pair<std::string, std::string> attack_type::damage_type() const
|
||||
{
|
||||
unit_ability_list abil_list = get_specials_and_abilities("damage");
|
||||
if(abil_list.empty()){
|
||||
return {type(), ""};
|
||||
}
|
||||
|
||||
std::vector<std::string> type_list = damage_type_list(abil_list, "replacement_type");
|
||||
std::vector<std::string> added_type_list = damage_type_list(abil_list, "alternative_type");
|
||||
std::string type_damage, sec_type_damage;
|
||||
type_damage = !type_list.empty() ? type_list.front() : type();
|
||||
sec_type_damage = !added_type_list.empty() ? added_type_list.front() : "";
|
||||
return {type_damage, sec_type_damage};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the damage per attack of this weapon, considering specials.
|
||||
|
|
|
@ -112,6 +112,8 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
const std::string& filter_attacks_used = filter["attacks_used"];
|
||||
const std::vector<std::string> filter_name = utils::split(filter["name"]);
|
||||
const std::vector<std::string> filter_type = utils::split(filter["type"]);
|
||||
const std::vector<std::string> filter_replacement_type = utils::split(filter["replacement_type"]);
|
||||
const std::vector<std::string> filter_alternative_type = utils::split(filter["alternative_type"]);
|
||||
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"]);
|
||||
|
@ -147,6 +149,20 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
if ( !filter_type.empty() && std::find(filter_type.begin(), filter_type.end(), attack.type()) == filter_type.end() )
|
||||
return false;
|
||||
|
||||
if(!filter_alternative_type.empty() || !filter_replacement_type.empty()){
|
||||
std::pair<std::string, std::string> damage_type = attack.damage_type();
|
||||
if(!filter_replacement_type.empty()){
|
||||
if ( std::find(filter_replacement_type.begin(), filter_replacement_type.end(), damage_type.first) == filter_replacement_type.end() ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!filter_alternative_type.empty()){
|
||||
if ( std::find(filter_alternative_type.begin(), filter_alternative_type.end(), damage_type.second) == filter_alternative_type.end() ){
|
||||
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;
|
||||
|
|
|
@ -88,6 +88,10 @@ public:
|
|||
/** Calculates the number of attacks this weapon has, considering specials. */
|
||||
void modified_attacks(unsigned & min_attacks,
|
||||
unsigned & max_attacks) 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;
|
||||
|
||||
/** Returns the damage per attack of this weapon, considering specials. */
|
||||
int modified_damage() const;
|
||||
|
||||
|
|
|
@ -1780,7 +1780,7 @@ bool unit::resistance_filter_matches(const config& cfg, bool attacker, const std
|
|||
|
||||
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 res = movement_type_.resistance_against(damage_name);
|
||||
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);
|
||||
utils::erase_if(resistance_abilities, [&](const unit_ability& i) {
|
||||
|
|
|
@ -334,6 +334,8 @@
|
|||
0 trait_requirement_test
|
||||
0 test_remove_ability_by_filter
|
||||
0 test_overwrite_specials_filter
|
||||
0 damage_type_test
|
||||
0 damage_secondary_type_test
|
||||
0 swarms_filter_student_by_type
|
||||
0 swarms_effects_not_checkable
|
||||
0 filter_special_id_active
|
||||
|
|
Loading…
Add table
Reference in a new issue