Add new attacks_used key to [attack] (#7351)
This commit is contained in:
parent
ec8ad5f26f
commit
cbbd34a79e
16 changed files with 190 additions and 6 deletions
2
changelog_entries/attacks_used.md
Normal file
2
changelog_entries/attacks_used.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
### WML API
|
||||
* New attacks_used key in [attack] causes the attack to deduct more than 1 from attacks left
|
|
@ -17,6 +17,7 @@
|
|||
{SIMPLE_KEY parry s_range_list}
|
||||
{SIMPLE_KEY accuracy s_range_list}
|
||||
{SIMPLE_KEY movement_used s_range_list}
|
||||
{SIMPLE_KEY attacks_used s_range_list}
|
||||
{FILTER_BOOLEAN_OPS weapon}
|
||||
[/tag]
|
||||
|
||||
|
|
|
@ -33,12 +33,14 @@
|
|||
{SIMPLE_KEY set_parry s_int}
|
||||
{SIMPLE_KEY set_accuracy s_int}
|
||||
{SIMPLE_KEY set_movement_used s_int}
|
||||
{SIMPLE_KEY set_attacks_used s_int}
|
||||
|
||||
{SIMPLE_KEY increase_damage s_int_percent}
|
||||
{SIMPLE_KEY increase_attacks s_int_percent}
|
||||
{SIMPLE_KEY increase_parry s_int_percent}
|
||||
{SIMPLE_KEY increase_accuracy s_int_percent}
|
||||
{SIMPLE_KEY increase_movement_used s_int_percent}
|
||||
{SIMPLE_KEY increase_attacks_used s_int_percent}
|
||||
|
||||
{SIMPLE_KEY attack_weight s_real}
|
||||
{SIMPLE_KEY defense_weight s_real}
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
{SIMPLE_KEY defense_weight real}
|
||||
{SIMPLE_KEY attack_weight real}
|
||||
{SIMPLE_KEY movement_used int}
|
||||
{SIMPLE_KEY attacks_used int}
|
||||
{SIMPLE_KEY accuracy int}
|
||||
{SIMPLE_KEY parry int}
|
||||
[tag]
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
{test/scenarios/wml_tests/TerrainWML}
|
||||
{test/scenarios/wml_tests/UnitsWML}
|
||||
{test/scenarios/wml_tests/UnitsWML/AbilitiesWML}
|
||||
{test/scenarios/wml_tests/UnitsWML/Attacks}
|
||||
{test/scenarios/wml_tests/WesnothFormulaLanguage}
|
||||
|
||||
# Load test unit wml
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#textdomain wesnoth-test
|
||||
|
||||
#####
|
||||
# API(s) being tested: [attack]attacks_used
|
||||
##
|
||||
# Expected end state:
|
||||
# The Elvish Archer (alice) has 3/5 attacks left after attacking the Orcish Grunt (bob)
|
||||
#####
|
||||
{COMMON_KEEP_A_B_UNIT_TEST test_attacks_used (
|
||||
[event]
|
||||
name=prestart
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_attacks_used=2
|
||||
[/effect]
|
||||
attacks_left=5
|
||||
[/modify_unit]
|
||||
[/event]
|
||||
[event]
|
||||
name=start
|
||||
[store_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
variable=alice
|
||||
[/store_unit]
|
||||
{ASSERT {VARIABLE_CONDITIONAL alice.attacks_left numerical_equals 5}}
|
||||
[do_command]
|
||||
[attack]
|
||||
weapon=0
|
||||
[source]
|
||||
x,y=4,3
|
||||
[/source]
|
||||
[destination]
|
||||
x,y=5,3
|
||||
[/destination]
|
||||
[/attack]
|
||||
[/do_command]
|
||||
[store_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
variable=alice
|
||||
[/store_unit]
|
||||
{ASSERT {VARIABLE_CONDITIONAL alice.attacks_left numerical_equals 3}}
|
||||
[do_command]
|
||||
[attack]
|
||||
weapon=1
|
||||
[source]
|
||||
x,y=4,3
|
||||
[/source]
|
||||
[destination]
|
||||
x,y=5,3
|
||||
[/destination]
|
||||
[/attack]
|
||||
[/do_command]
|
||||
[store_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
variable=alice
|
||||
[/store_unit]
|
||||
{ASSERT {VARIABLE_CONDITIONAL alice.attacks_left numerical_equals 2}}
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
)}
|
|
@ -0,0 +1,52 @@
|
|||
#textdomain wesnoth-test
|
||||
|
||||
#####
|
||||
# API(s) being tested: [attack]movement_used
|
||||
##
|
||||
# Expected end state:
|
||||
# The Elvish Archer (alice) has 5/6 move points left after attacking the Orcish Grunt (bob)
|
||||
#####
|
||||
{COMMON_KEEP_A_B_UNIT_TEST test_movement_used (
|
||||
[event]
|
||||
name=prestart
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to=attack
|
||||
range=melee
|
||||
set_movement_used=1
|
||||
[/effect]
|
||||
[/modify_unit]
|
||||
[/event]
|
||||
[event]
|
||||
name=start
|
||||
[store_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
variable=alice
|
||||
[/store_unit]
|
||||
{ASSERT {VARIABLE_CONDITIONAL alice.moves numerical_equals 6}}
|
||||
[do_command]
|
||||
[attack]
|
||||
weapon=0
|
||||
[source]
|
||||
x,y=4,3
|
||||
[/source]
|
||||
[destination]
|
||||
x,y=5,3
|
||||
[/destination]
|
||||
[/attack]
|
||||
[/do_command]
|
||||
[store_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
variable=alice
|
||||
[/store_unit]
|
||||
{ASSERT {VARIABLE_CONDITIONAL alice.moves numerical_equals 5}}
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
)}
|
|
@ -1369,11 +1369,10 @@ void attack::perform()
|
|||
return;
|
||||
}
|
||||
|
||||
a_.get_unit().set_attacks(a_.get_unit().attacks_left() - 1);
|
||||
|
||||
VALIDATE(a_.weapon_ < static_cast<int>(a_.get_unit().attacks().size()),
|
||||
_("An invalid attacker weapon got selected."));
|
||||
|
||||
a_.get_unit().set_attacks(a_.get_unit().attacks_left() - a_.get_unit().attacks()[a_.weapon_].attacks_used());
|
||||
a_.get_unit().set_movement(a_.get_unit().movement_left() - a_.get_unit().attacks()[a_.weapon_].movement_used(), true);
|
||||
a_.get_unit().set_state(unit::STATE_NOT_MOVED, false);
|
||||
a_.get_unit().set_resting(false);
|
||||
|
|
|
@ -107,6 +107,8 @@ variant attack_type_callable::get_value(const std::string& key) const
|
|||
return variant(att_->parry());
|
||||
} else if(key == "movement_used") {
|
||||
return variant(att_->movement_used());
|
||||
} else if(key == "attacks_used") {
|
||||
return variant(att_->attacks_used());
|
||||
} else if(key == "specials" || key == "special") {
|
||||
std::vector<variant> res;
|
||||
|
||||
|
@ -133,6 +135,7 @@ void attack_type_callable::get_inputs(formula_input_vector& inputs) const
|
|||
add_input(inputs, "accuracy");
|
||||
add_input(inputs, "parry");
|
||||
add_input(inputs, "movement_used");
|
||||
add_input(inputs, "attacks_used");
|
||||
add_input(inputs, "attack_weight");
|
||||
add_input(inputs, "defense_weight");
|
||||
add_input(inputs, "specials");
|
||||
|
|
|
@ -264,6 +264,7 @@ static int impl_unit_attack_get(lua_State *L)
|
|||
return_float_attrib("defense_weight", attack.defense_weight());
|
||||
return_int_attrib("accuracy", attack.accuracy());
|
||||
return_int_attrib("movement_used", attack.movement_used());
|
||||
return_int_attrib("attacks_used", attack.attacks_used());
|
||||
return_int_attrib("parry", attack.parry());
|
||||
return_cfgref_attrib("specials", attack.specials());
|
||||
return_cfgref_attrib("__cfg", attack.to_config());
|
||||
|
@ -296,6 +297,7 @@ static int impl_unit_attack_set(lua_State *L)
|
|||
modify_int_attrib("defense_weight", attack.set_defense_weight(value));
|
||||
modify_int_attrib("accuracy", attack.set_accuracy(value));
|
||||
modify_int_attrib("movement_used", attack.set_movement_used(value));
|
||||
modify_int_attrib("attacks_used", attack.set_attacks_used(value));
|
||||
modify_int_attrib("parry", attack.set_parry(value));
|
||||
|
||||
if(strcmp(m, "specials") == 0) {
|
||||
|
|
|
@ -65,6 +65,7 @@ attack_type::attack_type(const config& cfg) :
|
|||
defense_weight_(cfg["defense_weight"].to_double(1.0)),
|
||||
accuracy_(cfg["accuracy"]),
|
||||
movement_used_(cfg["movement_used"].to_int(100000)),
|
||||
attacks_used_(cfg["attacks_used"].to_int(1)),
|
||||
parry_(cfg["parry"]),
|
||||
specials_(cfg.child_or_empty("specials")),
|
||||
changed_(true)
|
||||
|
@ -108,6 +109,7 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
const std::string& filter_accuracy = filter["accuracy"];
|
||||
const std::string& filter_parry = filter["parry"];
|
||||
const std::string& filter_movement = filter["movement_used"];
|
||||
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_special = utils::split(filter["special"]);
|
||||
|
@ -136,6 +138,9 @@ static bool matches_simple_filter(const attack_type & attack, const config & fil
|
|||
if (!filter_movement.empty() && !in_ranges(attack.movement_used(), utils::parse_ranges(filter_movement)))
|
||||
return false;
|
||||
|
||||
if (!filter_attacks_used.empty() && !in_ranges(attack.attacks_used(), utils::parse_ranges(filter_attacks_used)))
|
||||
return false;
|
||||
|
||||
if ( !filter_name.empty() && std::find(filter_name.begin(), filter_name.end(), attack.id()) == filter_name.end() )
|
||||
return false;
|
||||
|
||||
|
@ -295,6 +300,8 @@ bool attack_type::apply_modification(const config& cfg)
|
|||
const std::string& set_parry = cfg["set_parry"];
|
||||
const std::string& increase_movement = cfg["increase_movement_used"];
|
||||
const std::string& set_movement = cfg["set_movement_used"];
|
||||
const std::string& increase_attacks_used = cfg["increase_attacks_used"];
|
||||
const std::string& set_attacks_used = cfg["set_attacks_used"];
|
||||
// NB: If you add something here that requires a description,
|
||||
// it needs to be added to describe_modification as well.
|
||||
|
||||
|
@ -396,6 +403,14 @@ bool attack_type::apply_modification(const config& cfg)
|
|||
movement_used_ = utils::apply_modifier(movement_used_, increase_movement, 1);
|
||||
}
|
||||
|
||||
if(set_attacks_used.empty() == false) {
|
||||
attacks_used_ = std::stoi(set_attacks_used);
|
||||
}
|
||||
|
||||
if(increase_attacks_used.empty() == false) {
|
||||
attacks_used_ = utils::apply_modifier(attacks_used_, increase_attacks_used, 1);
|
||||
}
|
||||
|
||||
if(set_attack_weight.empty() == false) {
|
||||
attack_weight_ = lexical_cast_default<double>(set_attack_weight,1.0);
|
||||
}
|
||||
|
@ -435,6 +450,8 @@ bool attack_type::describe_modification(const config& cfg,std::string* descripti
|
|||
const std::string& set_parry = cfg["set_parry"];
|
||||
const std::string& increase_movement = cfg["increase_movement_used"];
|
||||
const std::string& set_movement = cfg["set_movement_used"];
|
||||
const std::string& increase_attacks_used = cfg["increase_attacks_used"];
|
||||
const std::string& set_attacks_used = cfg["set_attacks_used"];
|
||||
|
||||
std::vector<t_string> desc;
|
||||
|
||||
|
@ -520,6 +537,24 @@ bool attack_type::describe_modification(const config& cfg,std::string* descripti
|
|||
{{"number_or_percent", utils::print_modifier(increase_movement)}, {"color", increase_movement[0] == '-' ? "#f00" : "#0f0"}}));
|
||||
}
|
||||
|
||||
if(!set_attacks_used.empty()) {
|
||||
desc.emplace_back(VNGETTEXT(
|
||||
// TRANSLATORS: Current value for WML code set_attacks_used, documented in https://wiki.wesnoth.org/EffectWML
|
||||
"$number attack used",
|
||||
"$number attacks used",
|
||||
std::stoi(set_attacks_used),
|
||||
{{"number", set_attacks_used}}));
|
||||
}
|
||||
|
||||
if(!increase_attacks_used.empty()) {
|
||||
desc.emplace_back(VNGETTEXT(
|
||||
// TRANSLATORS: Current value for WML code increase_attacks_used, documented in https://wiki.wesnoth.org/EffectWML
|
||||
"<span color=\"$color\">$number_or_percent</span> attack used",
|
||||
"<span color=\"$color\">$number_or_percent</span> attacks used",
|
||||
std::stoi(increase_attacks_used),
|
||||
{{"number_or_percent", utils::print_modifier(increase_attacks_used)}, {"color", increase_attacks_used[0] == '-' ? "#f00" : "#0f0"}}));
|
||||
}
|
||||
|
||||
*description = utils::format_conjunct_list("", desc);
|
||||
}
|
||||
|
||||
|
@ -541,6 +576,7 @@ void attack_type::write(config& cfg) const
|
|||
cfg["defense_weight"] = defense_weight_;
|
||||
cfg["accuracy"] = accuracy_;
|
||||
cfg["movement_used"] = movement_used_;
|
||||
cfg["attacks_used"] = attacks_used_;
|
||||
cfg["parry"] = parry_;
|
||||
cfg.add_child("specials", specials_);
|
||||
}
|
||||
|
|
|
@ -123,6 +123,8 @@ public:
|
|||
|
||||
int movement_used() const { return movement_used_; }
|
||||
void set_movement_used(int value) { movement_used_ = value; }
|
||||
int attacks_used() const { return attacks_used_; }
|
||||
void set_attacks_used(int value) { attacks_used_ = value; }
|
||||
|
||||
void write(config& cfg) const;
|
||||
inline config to_config() const { config c; write(c); return c; }
|
||||
|
@ -324,6 +326,7 @@ private:
|
|||
|
||||
int accuracy_;
|
||||
int movement_used_;
|
||||
int attacks_used_;
|
||||
int parry_;
|
||||
config specials_;
|
||||
bool changed_;
|
||||
|
|
|
@ -60,7 +60,9 @@ attack::attack(std::size_t team_index, bool hidden, unit& u, const map_location&
|
|||
target_hex_(target_hex),
|
||||
weapon_choice_(weapon_choice),
|
||||
attack_movement_cost_(u.attacks()[weapon_choice_].movement_used()),
|
||||
temp_movement_subtracted_(0)
|
||||
temp_movement_subtracted_(0),
|
||||
attack_count_(u.attacks()[weapon_choice_].attacks_used()),
|
||||
temp_attacks_subtracted_(0)
|
||||
{
|
||||
this->init();
|
||||
}
|
||||
|
@ -71,6 +73,8 @@ attack::attack(const config& cfg, bool hidden)
|
|||
, weapon_choice_(cfg["weapon_choice_"].to_int(-1)) //default value: -1
|
||||
, attack_movement_cost_()
|
||||
, temp_movement_subtracted_(0)
|
||||
, attack_count_()
|
||||
, temp_attacks_subtracted_(0)
|
||||
{
|
||||
// Validate target_hex
|
||||
if(!tiles_adjacent(target_hex_,get_dest_hex()))
|
||||
|
@ -83,6 +87,7 @@ attack::attack(const config& cfg, bool hidden)
|
|||
// Construct attack_movement_cost_
|
||||
assert(get_unit());
|
||||
attack_movement_cost_ = get_unit()->attacks()[weapon_choice_].movement_used();
|
||||
attack_count_ = get_unit()->attacks()[weapon_choice_].attacks_used();
|
||||
|
||||
this->init();
|
||||
}
|
||||
|
@ -155,16 +160,17 @@ void attack::apply_temp_modifier(unit_map& unit_map)
|
|||
assert(get_unit());
|
||||
unit& unit = *get_unit();
|
||||
DBG_WB << unit.name() << " [" << unit.id()
|
||||
<< "] has " << unit.attacks_left() << " attacks, decreasing by one";
|
||||
assert(unit.attacks_left() > 0);
|
||||
unit.set_attacks(unit.attacks_left() - 1);
|
||||
<< "] has " << unit.attacks_left() << " attacks, decreasing by " << attack_count_;
|
||||
assert(unit.attacks_left() > attack_count_);
|
||||
|
||||
//Calculate movement to subtract
|
||||
temp_movement_subtracted_ = unit.movement_left() >= attack_movement_cost_ ? attack_movement_cost_ : 0 ;
|
||||
temp_attacks_subtracted_ = unit.attacks_left() >= attack_count_ ? attack_count_ : 0 ;
|
||||
DBG_WB << "Attack: Changing movement points for unit " << unit.name() << " [" << unit.id()
|
||||
<< "] from " << unit.movement_left() << " to "
|
||||
<< unit.movement_left() - temp_movement_subtracted_ << ".";
|
||||
unit.set_movement(unit.movement_left() - temp_movement_subtracted_, true);
|
||||
unit.set_attacks(unit.attacks_left() - temp_attacks_subtracted_);
|
||||
|
||||
//Update status of fake unit (not undone by remove_temp_modifiers)
|
||||
//@todo this contradicts the name "temp_modifiers"
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
int weapon_choice_;
|
||||
int attack_movement_cost_;
|
||||
int temp_movement_subtracted_;
|
||||
int attack_count_;
|
||||
int temp_attacks_subtracted_;
|
||||
};
|
||||
|
||||
/** Dumps an attack on a stream, for debug purposes. */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
---@field range integer
|
||||
---@field number integer
|
||||
---@field movement_used integer
|
||||
---@field attacks_used integer
|
||||
---@field attack_weight number
|
||||
---@field defense_weight number
|
||||
---@field accuracy integer
|
||||
|
|
|
@ -203,6 +203,8 @@
|
|||
0 special_note_from_movetype
|
||||
0 special_note_individual_unit
|
||||
0 has_achievement
|
||||
0 test_movement_used
|
||||
0 test_attacks_used
|
||||
# Terrain mask tests
|
||||
0 test_terrain_mask_simple_nop
|
||||
0 test_terrain_mask_simple_set
|
||||
|
|
Loading…
Add table
Reference in a new issue