UNIT_FACTION fires on the faction template's own edge (#858)
A target whose faction template the server swaps live (35 to 14, neither naming a faction group) kept its friendly plate colour: `UNIT_FACTION` fired only when the pvp, FFA, faction-group or tapped state moved. The reference's per-field watch fires `UNIT_FACTION` on any change of `UNIT_FIELD_FACTIONTEMPLATE`, as it fires `UNIT_FLAGS` for that field. `fire_transitions` now also fires it on the faction template's edge. Test: `a_live_faction_template_change_recolours_the_target_plate`. From #855 by @kalistoking, landed here because the fork refuses maintainer pushes. Co-authored-by: kalistoking <148718830+kalistoking@users.noreply.github.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
kalistoking
Claude Opus 5.5
parent
45da0a0850
commit
ff49eb5b8f
@@ -958,6 +958,57 @@ fn an_exalted_npc_target_reads_revered_and_its_plate_is_green() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A target whose faction template the server changes live recolours its plate: template 35
|
||||
/// (friendly) to 14 (hostile) names no side either way, so only the template's own edge fires
|
||||
/// `UNIT_FACTION`. No edge, or another unit's, leaves the plate as it was.
|
||||
#[test]
|
||||
fn a_live_faction_template_change_recolours_the_target_plate() {
|
||||
benilla_formats::wow_data_or_skip!();
|
||||
use crate::net::FieldEdges;
|
||||
use benilla_protocol::field::FIELD_UNIT_FACTIONTEMPLATE;
|
||||
|
||||
const MOB: u64 = 0xF130_0000_3796_0001;
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1024.0, 768.0);
|
||||
load_unit_frames(&s);
|
||||
let mob = |reaction: u8| UnitState {
|
||||
exists: true,
|
||||
has_object: true,
|
||||
guid: MOB,
|
||||
name: Some("Pusillin".into()),
|
||||
health: 100,
|
||||
max_health: 100,
|
||||
level: 58,
|
||||
reaction,
|
||||
can_attack: reaction < 4,
|
||||
..UnitState::default()
|
||||
};
|
||||
let is_green = |c: [f32; 4]| c[0].abs() < 1e-6 && (c[1] - 1.0).abs() < 1e-6;
|
||||
let is_red = |c: [f32; 4]| (c[0] - 1.0).abs() < 1e-6 && c[1].abs() < 1e-6;
|
||||
|
||||
let friendly = mob(5);
|
||||
s.set_unit("target", Some(friendly.clone()));
|
||||
s.fire_event("PLAYER_TARGET_CHANGED", vec![]);
|
||||
let before = plate_color(&mut s);
|
||||
assert!(is_green(before), "template 35 reads green, got {before:?}");
|
||||
|
||||
let hostile = mob(2);
|
||||
s.set_unit("target", Some(hostile.clone()));
|
||||
let fire = |s: &mut UiScript, prev: &UnitState, edges: &[(u64, u16)]| {
|
||||
crate::ui_unit::fire_transitions(s, "target", Some(prev), &hostile, &FieldEdges::of(edges));
|
||||
};
|
||||
fire(&mut s, &friendly, &[]);
|
||||
let stale = plate_color(&mut s);
|
||||
assert!(is_green(stale), "no edge, no repaint, got {stale:?}");
|
||||
fire(&mut s, &hostile, &[(MOB + 1, FIELD_UNIT_FACTIONTEMPLATE)]);
|
||||
let other = plate_color(&mut s);
|
||||
assert!(is_green(other), "another unit's edge, got {other:?}");
|
||||
fire(&mut s, &hostile, &[(MOB, FIELD_UNIT_FACTIONTEMPLATE)]);
|
||||
let after = plate_color(&mut s);
|
||||
assert!(is_red(after), "template 14 reads red, got {after:?}");
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
/// Stock `TargetFrame_CheckClassification` (`TargetFrame.lua:205-218`), asserted on the drawn
|
||||
/// quads: elite, rare-elite and world boss share the Elite art (1.12 ships no rare-elite border),
|
||||
/// and `UNIT_CLASSIFICATION_CHANGED` alone repaints it.
|
||||
|
||||
@@ -1185,11 +1185,19 @@ pub(crate) fn fire_transitions(
|
||||
}
|
||||
// `UNIT_FACTION`, the PvP-icon repaint, on the fields the icon reads and on the tapped bit: the
|
||||
// reference's dynamic-flags watcher (`0x600440`) fires event 29 on bit `0x4` (`0x6005a1` →
|
||||
// `0x6005b0`) and has no arm for `0x8`.
|
||||
if prev.is_none_or(|p| {
|
||||
(p.pvp, p.is_pvp_ffa, &p.faction_group, p.tapped)
|
||||
!= (cur.pvp, cur.is_pvp_ffa, &cur.faction_group, cur.tapped)
|
||||
}) {
|
||||
// `0x6005b0`) and has no arm for `0x8`. Also on any change of `UNIT_FIELD_FACTIONTEMPLATE`, the
|
||||
// watch bridge's id 29 (`0x51bbb0`, as for `UNIT_FLAGS` above): a template swap between two
|
||||
// that name no faction group moves nothing in the tuple, yet changes the reaction.
|
||||
let template_moved = edges.moved(
|
||||
cur.guid,
|
||||
benilla_protocol::field::FIELD_UNIT_FACTIONTEMPLATE,
|
||||
);
|
||||
if template_moved
|
||||
|| prev.is_none_or(|p| {
|
||||
(p.pvp, p.is_pvp_ffa, &p.faction_group, p.tapped)
|
||||
!= (cur.pvp, cur.is_pvp_ffa, &cur.faction_group, cur.tapped)
|
||||
})
|
||||
{
|
||||
script.fire_event("UNIT_FACTION", vec![tok()]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user