Add unit_hits, unit_misses events

Added new events "unit hits/misses" to simplify creating events that use attacker+defender hits/misses (issue #7782)
This commit is contained in:
Toom 2024-06-30 13:02:55 +03:00 committed by GitHub
parent 55b6010f77
commit 081866af7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 52 additions and 9 deletions

View file

@ -1,14 +1,17 @@
#textdomain wesnoth-test
#####
# API(s) being tested: [event]name=unit placed,prerecruit,recruit,exit_hex,enter_hex,moveto,pre_attack,attack,attacker hits,defender misses,attack end,attacker misses,defender hits,pre advance,advance,post advance
# API(s) being tested: [event]name=unit placed,prerecruit,recruit,exit_hex,enter_hex,moveto,pre_attack,attack,attacker hits,unit hits,defender misses,unit misses,attack end,attacker misses,unit misses,defender hits,unit hits,pre advance,advance,post advance
##
# Actions:
# alice recruits unit
# Trigger attack from alice to bob where alice always hits and bob always misses
# Trigger attack from bob to alice where alice always hits and bob always misses
# Trigger various sets of events and check that they are executed in the proper sequence.
##
# Expected end state:
# unit placed -> prerecruit -> recruit
# exit_hex -> enter_hex -> moveto
# pre_attack -> attack -> attacker hits/attacker misses -> defender hits/defender misses -> attack end
# pre_attack -> attack -> attacker hits/attacker misses -> unit hits/misses -> defender hits/defender misses -> unit hits/misses -> attack end
# pre advance -> advance -> post advance
#####
{GENERIC_UNIT_TEST "events-test_filterable1" (
@ -153,6 +156,34 @@
name=defender misses
{VARIABLE defender_misses_flag 1}
[/event]
[event]
name=unit hits
[filter]
id=alice
[/filter]
{VARIABLE alice_unit_hits_flag 1}
[/event]
[event]
name=unit misses
[filter]
id=alice
[/filter]
{VARIABLE alice_unit_misses_flag 1}
[/event]
[event]
name=unit hits
[filter]
id=bob
[/filter]
{VARIABLE bob_unit_hits_flag 1}
[/event]
[event]
name=unit misses
[filter]
id=bob
[/filter]
{VARIABLE bob_unit_misses_flag 1}
[/event]
[event]
name=attack end
{VARIABLE attack_end_flag 1}
@ -197,6 +228,10 @@
{FAIL_IF_NOT attack_end_flag 1}
{FAIL_IF_NOT attacker_misses_flag 1}
{FAIL_IF_NOT defender_hits_flag 1}
{FAIL_IF_NOT alice_unit_hits_flag 1}
{FAIL_IF_NOT alice_unit_misses_flag $null}
{FAIL_IF_NOT bob_unit_hits_flag $null}
{FAIL_IF_NOT bob_unit_misses_flag 1}
{FAIL_IF_NOT pre_advance_flag 1}
{FAIL_IF_NOT advance_flag 1}
{FAIL_IF_NOT post_advance_flag 1}

View file

@ -709,6 +709,7 @@ private:
bool perform_hit(bool, statistics_attack_context&);
void fire_event(const std::string& n);
void fire_event_impl(const std::string& n, bool reversed);
void refresh_bc();
/** Structure holding unit info used in the attack action. */
@ -844,13 +845,18 @@ attack::attack(const map_location& attacker,
}
void attack::fire_event(const std::string& n)
{
fire_event_impl(n, false);
}
void attack::fire_event_impl(const std::string& n, bool reverse)
{
LOG_NG << "attack: firing '" << n << "' event";
// prepare the event data for weapon filtering
config ev_data;
config& a_weapon_cfg = ev_data.add_child("first");
config& d_weapon_cfg = ev_data.add_child("second");
config& a_weapon_cfg = ev_data.add_child(reverse ? "second" : "first");
config& d_weapon_cfg = ev_data.add_child(reverse ? "first" : "second");
// Need these to ensure weapon filters work correctly
std::optional<attack_type::specials_context_t> a_ctx, d_ctx;
@ -887,9 +893,9 @@ void attack::fire_event(const std::string& n)
return;
}
// damage_inflicted is set in these two events.
// damage_inflicted is set in these events.
// TODO: should we set this value from unit_info::damage, or continue using the WML variable?
if(n == "attacker_hits" || n == "defender_hits") {
if(n == "attacker_hits" || n == "defender_hits" || n == "unit_hits") {
ev_data["damage_inflicted"] = resources::gamedata->get_variable("damage_inflicted");
}
@ -897,8 +903,8 @@ void attack::fire_event(const std::string& n)
bool wml_aborted;
std::tie(std::ignore, wml_aborted) = resources::game_events->pump().fire(n,
game_events::entity_location(a_.loc_, a_.id_),
game_events::entity_location(d_.loc_, d_.id_), ev_data);
game_events::entity_location(reverse ? d_.loc_ : a_.loc_, reverse ? d_.id_ : a_.id_),
game_events::entity_location(reverse ? a_.loc_ : d_.loc_, reverse ? a_.id_ : d_.id_), ev_data);
// The event could have killed either the attacker or
// defender, so we have to make sure they still exist.
@ -1125,6 +1131,7 @@ bool attack::perform_hit(bool attacker_turn, statistics_attack_context& stats)
if(hits) {
try {
fire_event(attacker_turn ? "attacker_hits" : "defender_hits");
fire_event_impl("unit_hits", !attacker_turn);
} catch(const attack_end_exception&) {
refresh_bc();
return false;
@ -1132,6 +1139,7 @@ bool attack::perform_hit(bool attacker_turn, statistics_attack_context& stats)
} else {
try {
fire_event(attacker_turn ? "attacker_misses" : "defender_misses");
fire_event_impl("unit_misses", !attacker_turn);
} catch(const attack_end_exception&) {
refresh_bc();
return false;
@ -1450,7 +1458,7 @@ void attack::perform()
}
}
// Set by attacker_hits and defender_hits events.
// Set by attacker_hits and defender_hits and unit_hits events.
resources::gamedata->clear_variable("damage_inflicted");
if(update_def_fog_) {