a nameplate takes a right-click, and four wrong verb rows come off

- a right-click on a nameplate selects and interacts again: the plate registers the right button, as the reference's does (2233)
- the verb-events table files each fire site against its function's verified extent, and four rows it had misattributed are gone (2257)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-09-16 06:39:15 +07:00
co-authored by Claude Fable 5.1
parent 5c9d919a0c
commit 60bb2e3d6d
3 changed files with 83 additions and 35 deletions
@@ -57,11 +57,6 @@ struct Pair {
/// written — the trigger is named so the next reader can check it in one grep.
const ELSEWHERE: &[(&str, &str, &str)] = &[
// The sell slot's diff (`auction_sell_item` moved, or `sell_slot_dirty`).
(
"CalculateAuctionDeposit",
"NEW_AUCTION_UPDATE",
"benilla-app/src/ui_auction/mod.rs",
),
(
"ClickAuctionSellItemButton",
"NEW_AUCTION_UPDATE",
@@ -146,12 +141,6 @@ const ELSEWHERE: &[(&str, &str, &str)] = &[
"UPDATE_BINDINGS",
"benilla-app/src/bindings.rs",
),
// A `SessionRequest::StopCinematic`; the player stops, and the flip to not-playing fires.
(
"StopCinematic",
"CINEMATIC_STOP",
"benilla-app/src/cinematic.rs",
),
// The toggle goes to the wire and the bar's pushed key changes on the reply — one round trip
// later than the reference, which fires locally from the toggle.
(
@@ -172,54 +161,54 @@ const GAP: &[(&str, &str, &str)] = &[
(
"CancelSkillUps",
"SKILL_LINES_CHANGED",
"resets temp skill points over a table this model keeps empty (`skills.rs`), so nothing \
moves and `ui_char.rs`'s feed has nothing to announce; the reference fires from \
0x4d3e3a regardless",
"the reference's verb (0x4d3e30) calls the temp-point reset and fires unconditionally at \
0x4d3e35; here the reset runs over a table this model keeps empty (`skills.rs`), so \
nothing moves and `ui_char.rs`'s feed has nothing to announce — the stock SkillFrame \
would only repaint under its own Close",
),
(
"ClickTargetTradeButton",
"TRADE_REPLACE_ENCHANT",
"the trade-window enchant leg (0592 P3) is not built; the verb is the money arm only",
"the reference runs the enchant clash check 0x496170 when a spell is on the cursor and \
fires this for the replace dialog (wow-re staticpopup-dialog-bindings.md §3.1); casting \
an enchant onto the partner's slot is not built here — `ui_trade.rs` only mirrors the \
wire's enchant slot — so the verb is the money arm alone",
),
(
"CloseTrade",
"PLAYER_TRADE_MONEY",
"`ui_trade.rs` announces money only while the trade is open; the reference's close zeroes \
the offer and fires from 0x4bfdce, under a frame that TRADE_CLOSED hides first",
"fired only when the trade did not complete (`[0xb71748] == 0`, wow-re \
incoming-trade-request-law.md), zeroing the cancelled offer under a frame TRADE_CLOSED \
hides; here `TradeSession::begin` resets the whole session at the next trade, so the \
next window opens at zero either way",
),
(
"CollapseCraftSkillLine",
"CRAFT_UPDATE",
"a no-op here: the craft list is flat, the header law was never ported from TradeSkill \
(0446, 0530's follow-up), so there is nothing to repaint",
"the reference commits through the 21-byte thunk 0x4f6be0 (the trainer's 0x4d8c90 shape); \
a no-op here because the craft list is flat — the header law was never ported from \
TradeSkill (0446, 0530's follow-up) — so there is nothing to repaint. Whether any 1.12 \
craft list carries more than one group is not established: 0446 covers Enchanting, \
Beast Training is unchecked",
),
(
"ExpandCraftSkillLine",
"CRAFT_UPDATE",
"the same no-op as CollapseCraftSkillLine",
"the same thunk and the same no-op as CollapseCraftSkillLine",
),
(
"PetDismiss",
"PET_DISMISS_START",
"no shipped file listens; the dismiss reaches the wire through the app's drain and the \
pet frame follows the unit's departure",
"the worker 0x4bd6e0 sends the dismiss and fires this with a duration (`%d`, 10000 — \
wow-re pet-action-bar-api.md §10.8); no shipped file listens, the dismiss reaches the \
wire through the app's drain, and the pet frame follows the unit's departure",
),
(
"SelectGossipOption",
"GOSSIP_ENTER_CODE",
"the code-entry gossip option kind is not modelled (`reference_ui`'s UNPRODUCED row)",
),
(
"SetPetStablePaperdoll",
"PET_STABLE_UPDATE_PAPERDOLL",
"inert by design: the stable's model pane is an app-side booth that follows the selection \
every frame (1676), so the VM has nothing to point",
),
(
"UpdateMapHighlight",
"CLOSE_WORLD_MAP",
"0x4a7620 fires it (site 0x4a7835, id 373) on a path the highlight verb reaches under a \
condition nobody has read; unbuilt until carved",
"a coded option raises the code-entry popup in the reference (the worker 0x4e2320); here \
coded options are greyed and unselectable (0081 v1, `reference_ui`'s UNPRODUCED row), and \
vmangos's `gossip_menu_option` carries zero coded rows, so no NPC on this server reaches it",
),
];
+15
View File
@@ -499,6 +499,21 @@ impl Plate {
// app through [`UiScript::hovered_nameplate`] and [`UiScript::take_nameplate_clicks`].
// `EnableMouse`/`IsMouseEnabled` are in the corpus's own call set, and pfUI's vanilla
// click-through block drives them.
//
// **And it takes BOTH buttons, on the UP edge**: `RegisterForClicks(0x500)` at `0x7cb637`
// (`0x779730` → `[this+0x330] = 0x500` = LeftButtonUp | RightButtonUp). The arena's Button
// default is `{"LeftButtonUp"}` alone, so without this a physical right-click on a plate
// fired no click at all — [`super::button::wants_click`] refused the release, the funnel
// never ran, and since 2233 took the camera off a press that lands on a plate there was no
// other path left: right-clicking a nameplate did nothing. The reference's own slot
// (`0x7cb910`) takes mask 1 → `0x4925d0` select and mask 4 → `0x492820` select+interact.
if let Some(KindState::Button(bs)) = model.arena.frame_mut(frame).map(|f| &mut f.kind_state)
{
bs.registered_clicks = ["LeftButtonUp", "RightButtonUp"]
.into_iter()
.map(str::to_string)
.collect();
}
// The blend modes are the ctor's own, one `0x7703f0` call per texture (wow-re
// `nameplate-vkey.md` §8.1, byte-arbitrated): everything is BLEND(2) except the **glow,
@@ -703,6 +703,50 @@ fn a_completed_click_on_a_plate_reaches_the_app() {
);
}
/// **The right button too** — `RegisterForClicks(0x500)` is LeftButtonUp | **RightButtonUp**
/// (`0x7cb637` → `[this+0x330]`), and the reference's slot forks on it: mask 1 → `0x4925d0`
/// select, mask 4 → `0x492820` select **and interact** (decision 2233, wow-re
/// `ui/scratch/mouselook-mouseover-and-nameplate-click-law.md` §6.4).
///
/// The regression this pins: a plate is created as a plain `Button`, whose default registered set
/// is `{"LeftButtonUp"}` alone, so the release was refused before the click funnel — and with 2233
/// taking the camera off a press that lands on a plate, that left right-clicking a nameplate doing
/// nothing whatsoever.
#[test]
fn a_physical_right_click_on_a_plate_reaches_the_app() {
let mut s = vm();
let wolf = plate("Wolf", 30.0, 40.0);
let key = wolf.key;
drive(&mut s, &[wolf]);
s.mouse_move(500.0, 384.0);
s.mouse_button(500.0, 384.0, "RightButton", true);
assert!(
s.take_nameplate_clicks().is_empty(),
"the UP lane only: `0x500` has no ButtonDown bit"
);
s.mouse_button(500.0, 384.0, "RightButton", false);
let clicks = s.take_nameplate_clicks();
assert_eq!(clicks.len(), 1);
assert_eq!(clicks[0].key, key);
assert_eq!(clicks[0].button, "RightButton");
}
/// A button the plate never registered fires nothing — the mask is exactly `0x500`, not "any
/// button".
#[test]
fn a_middle_click_on_a_plate_fires_nothing() {
let mut s = vm();
drive(&mut s, &[plate("Wolf", 30.0, 40.0)]);
s.mouse_move(500.0, 384.0);
s.mouse_button(500.0, 384.0, "MiddleButton", true);
s.mouse_button(500.0, 384.0, "MiddleButton", false);
assert!(
s.take_nameplate_clicks().is_empty(),
"`0x500` is Left|Right on the up edge and nothing else"
);
}
/// pfUI's click-through calls `plate:Click("LeftButton")` (`nameplates.lua:1274`), and
/// CustomNameplates and `_Nameplates` do the same. A scripted click has to select the unit like a
/// physical one — in the reference both go through the button's one click slot, and here they go