fix: overhead names carry the player's PvP title, as 1.12.1 does (#792)

- capture: a name-rank scenario shoots a ranked player's overhead name line
- Overhead names carry the player's PvP title under UnitNamePlayerPVPTitle, as 1.12.1 does (#550)
- review: bundle the rank-title inputs; doc the snapshot and rank-19 limits
- nameplates: read rank strings per VM; test the composed name line
- pvp: correct the rank-title docs; convert the credit team without a cast
- Fix the titles row comment; name-rank reuses WOLF_POS, cites :900
- rank strings: the honor feed reads them off the VM; nameplates only reads the value

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
This commit is contained in:
goran2711
2026-10-04 11:04:32 +07:00
committed by GitHub
co-authored by Claude Opus 5.5 Sam
parent aa103d5a65
commit 622e1c3e7a
11 changed files with 793 additions and 146 deletions
@@ -1346,14 +1346,17 @@ fn the_nameplates_page_toggles_the_unit_name_cvars() {
"{row} defaults unchecked"
);
}
// The name rows at the reference's registered defaults: player "1", NPC and own "0".
assert!(
s.eval::<bool>(
"return BenillaOptionsFrameContainerBodyNameplatesRowPlayerNamesCheck:GetChecked()"
)
.unwrap(),
"Player Names defaults checked"
);
// The name rows at the reference's registered defaults: player, guild and titles "1", NPC and
// own "0".
for row in ["RowPlayerNames", "RowGuildNames", "RowPlayerTitles"] {
assert!(
s.eval::<bool>(&format!(
"return BenillaOptionsFrameContainerBodyNameplates{row}Check:GetChecked()"
))
.unwrap(),
"{row} defaults checked"
);
}
for row in ["RowNpcNames", "RowOwnName"] {
assert!(
!s.eval::<bool>(&format!(
@@ -2314,9 +2317,9 @@ fn every_row_tooltip_key_resolves_in_the_real_global_strings() {
);
checked += 1;
}
// 83 rows less the three untipped below; four of the 80 carry a `BENILLA_` key, and a dropdown
// 84 rows less the three untipped below; four of the 81 carry a `BENILLA_` key, and a dropdown
// row is checked on the key it wears at rest.
assert_eq!(checked, 80, "every tipped row carries a live key");
assert_eq!(checked, 81, "every tipped row carries a live key");
assert_eq!(
untipped,
vec![
@@ -2412,8 +2415,8 @@ fn every_flavor_of_row_raises_its_plate_from_the_page_it_lives_on() {
s.errors()
);
}
// Every tipped row: the same 80 the key census counts.
assert_eq!(raised, 80, "every row but Auto Loot raises a description");
// Every tipped row: the same 81 the key census counts.
assert_eq!(raised, 81, "every row but Auto Loot raises a description");
}
/// 1.12's AdvancedOptionsCombatText box as saved-global rows: a click writes the global, never a
@@ -4069,13 +4072,6 @@ fn without_a_seated_measurer_the_same_fit_reads_zero() {
// nothing and reads back nil, so its box would offer a setting benilla does not have. A CVar is
// registered only once something reads it.
const UNBACKED_REFERENCE_CVARS: &[(&str, &str)] = &[
(
"UnitNamePlayerPVPTitle",
"the PvP rank prefix on the overhead name line — slot a4 of `0x608f50`, bit `0x20` of the \
same mask, resolved by `0x609370` through the `PVP_RANK_%d_%d` GlobalStrings key. Blocked \
one step further back than its guild twin: the rank byte streams, but the key's second \
index is a FACTION SIDE that `ui_unit` does not resolve for an arbitrary player yet",
),
// No slider CVar may land here: `UIOptionsFrame_Load` hands `GetCVar` to `Slider:SetValue`
// (`UIOptionsFrame.lua:271-275`), which raises on nil (`0x790980`) and stops the stock
// window's load. A check button's `GetCVar(x) == "1"` is nil-safe.
@@ -4379,7 +4375,48 @@ fn show_target_damage_greys_its_own_pair_and_the_floating_text_master_leaves_it_
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
/// The reference's rules: Player Guild Names is dead while player names are off
/// The titles box is the guild row's twin: checked and live at the registered defaults (`"1"`),
/// and a click survives closing and reopening the panel because the CVar is its store.
#[test]
fn the_titles_box_sticks_across_a_panel_reopen() {
benilla_formats::wow_data_or_skip!();
let mut s = harness_on(audio_harness());
s.run("ShowUIPanel(BenillaOptionsFrame)").unwrap();
s.run("BenillaOptionsFrameCategoryListRowNameplates:Click()")
.unwrap();
let checked = |s: &mut UiScript| -> bool {
s.eval::<bool>(
"return BenillaOptionsFrameContainerBodyNameplatesRowPlayerTitlesCheck:GetChecked()",
)
.unwrap()
};
let cvar = |s: &mut UiScript| -> Option<String> {
s.eval::<Option<String>>(r#"return GetCVar("UnitNamePlayerPVPTitle")"#)
.unwrap()
};
assert!(checked(&mut s), "the registered default is \"1\"");
assert_eq!(cvar(&mut s).as_deref(), Some("1"));
// A click writes the CVar; the box and the mirror agree.
s.run("BenillaOptionsFrameContainerBodyNameplatesRowPlayerTitlesCheck:Click()")
.unwrap();
assert!(!checked(&mut s));
assert_eq!(cvar(&mut s).as_deref(), Some("0"));
// Closed and reopened, the row re-reads the CVar instead of a staged value.
s.run("HideUIPanel(BenillaOptionsFrame) ShowUIPanel(BenillaOptionsFrame)")
.unwrap();
s.run("BenillaOptionsFrameCategoryListRowNameplates:Click()")
.unwrap();
assert!(!checked(&mut s), "the click stuck");
s.run("BenillaOptionsFrameContainerBodyNameplatesRowPlayerTitlesCheck:Click()")
.unwrap();
assert!(checked(&mut s));
assert_eq!(cvar(&mut s).as_deref(), Some("1"));
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
/// The reference's rules: Player Guild Names and Player Titles are dead while player names are off
/// (`UIOptionsFrame.lua:703-709`), Auto-Follow Speed while the style is Never (`:717-721`).
#[test]
fn the_guild_line_greys_with_player_names_and_the_follow_speed_with_the_style() {
@@ -4387,22 +4424,28 @@ fn the_guild_line_greys_with_player_names_and_the_follow_speed_with_the_style()
let mut s = harness_on(audio_harness());
s.run("ShowUIPanel(BenillaOptionsFrame)").unwrap();
// Nameplates: `UnitNamePlayer` ships "1", so the child arrives live.
// Nameplates: `UnitNamePlayer` ships "1", so both children arrive live.
s.run("BenillaOptionsFrameCategoryListRowNameplates:Click()")
.unwrap();
let guild_on = |s: &mut UiScript| -> bool {
s.eval::<bool>(
"return BenillaOptionsFrameContainerBodyNameplatesRowGuildNamesCheck:IsEnabled() ~= 0",
)
let child_on = |s: &mut UiScript, row: &str| -> bool {
s.eval::<bool>(&format!(
"return BenillaOptionsFrameContainerBodyNameplates{row}Check:IsEnabled() ~= 0"
))
.unwrap()
};
assert!(guild_on(&mut s));
for row in ["RowGuildNames", "RowPlayerTitles"] {
assert!(child_on(&mut s, row), "{row} arrives live");
}
s.run("BenillaOptionsFrameContainerBodyNameplatesRowPlayerNamesCheck:Click()")
.unwrap();
assert!(!guild_on(&mut s), "no names, no guild line to gate");
for row in ["RowGuildNames", "RowPlayerTitles"] {
assert!(!child_on(&mut s, row), "no names, no {row} to gate");
}
s.run("BenillaOptionsFrameContainerBodyNameplatesRowPlayerNamesCheck:Click()")
.unwrap();
assert!(guild_on(&mut s));
for row in ["RowGuildNames", "RowPlayerTitles"] {
assert!(child_on(&mut s, row));
}
// Controls: the style ships "1" (Smart), so the slider arrives live; "0" is Never.
s.run("BenillaOptionsFrameCategoryListRowControls:Click()")