From 081866af7b5d52394ad5eaadedc19a364e0b8b35 Mon Sep 17 00:00:00 2001 From: Toom Date: Sun, 30 Jun 2024 13:02:55 +0300 Subject: [PATCH] Add unit_hits, unit_misses events Added new events "unit hits/misses" to simplify creating events that use attacker+defender hits/misses (issue #7782) --- .../EventWML/events-test_filterable1.cfg | 39 ++++++++++++++++++- src/actions/attack.cpp | 22 +++++++---- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/data/test/scenarios/wml_tests/ScenarioWML/EventWML/events-test_filterable1.cfg b/data/test/scenarios/wml_tests/ScenarioWML/EventWML/events-test_filterable1.cfg index 3d841456a35..a895ba8720b 100644 --- a/data/test/scenarios/wml_tests/ScenarioWML/EventWML/events-test_filterable1.cfg +++ b/data/test/scenarios/wml_tests/ScenarioWML/EventWML/events-test_filterable1.cfg @@ -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} diff --git a/src/actions/attack.cpp b/src/actions/attack.cpp index b7d23559e5b..6f01ca52433 100644 --- a/src/actions/attack.cpp +++ b/src/actions/attack.cpp @@ -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 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_) {