Files
benilla-octo/crates/benilla-ui/src/script/ui_errors.rs
T
SamandClaude Fable 5 9bd2609740 windows take turns, the gossip page waits, the shot bar counts down
- the UIPanel registry is re-derived from the reference's bytes: the readable-item page finally registers, so a note or letter closes when a gossip window opens instead of interleaving with it line for line; the character sheet takes its real pushable-2 seat (an NPC window slides it over instead of replacing it), and the spellbook, quest log, talents and character sheet open for dead players again — a refused open now says "You can't do that when you're dead." instead of doing nothing
- the gossip window waits for its greeting: the first packet carries only the options and a text id, and we used to show the frame with a blank page for the round trip the text needed — the menu now exists only once the text has answered, a mid-flight click is refused, and a revisit is instant off the cache
- a bag slot whose stack count changes on the server now fires `ITEM_LOCK_CHANGED` just ahead of its `BAG_UPDATE` — the one signal 1.12 hunter addons use to detect a spent arrow — so Quiver's auto-shot bar drains per shot instead of pinning at 100%; a swap or create deliberately does not fire it, so rearranging bags can't read as a shot
- the outdoor minimap tiles' gamma byte reaches the screen exactly once — the ordinary decode arm learns the same skip the fast path already had

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:17:03 +07:00

36 lines
1.8 KiB
Rust

//! **The Lua-callable half of the client-local error-display family** — FrameXML-facing globals
//! whose whole body, in the reference binary, is "push one catalog id at
//! `CGGameUI::DisplayError`'s dispatcher". The engine-side half (a Rust system raising a key
//! directly, e.g. the passive-on-bar refusal) pushes onto the same [`Model::ui_errors`] queue;
//! the app drains it, resolves each key against the VM's own GlobalStrings and fires
//! `UI_ERROR_MESSAGE` (`ui_action/feed.rs`) — which is byte-for-byte the reference route: catalog
//! row → GlobalStrings text → FrameScript event `0xe0`, rendered by UIErrorsFrame.
//!
//! First tenant: `NotWhileDeadError` (decision 1507's open item, closed by the wow-re §5
//! cross-check of 2026-08-21, recorded in wow-re `system/ui`): registration pair `0x83e398`,
//! C body `0x48d340` = `push 0x7e; call 0x496720; xor eax,eax; ret` — no argument read, no
//! dead-check of its own, 0 return values, and its catalog row (`0xb4be70`, key
//! `ERR_PLAYER_DEAD`) names sound `"NONE"`, so the toast is silent. FrameXML decides *when* to
//! call it (ShowUIPanel's `whileDead` refusal, UIParent.lua l.663-666; ContainerFrame.lua l.147
//! and l.190); the binding only displays.
use mlua::Lua;
use super::model::Model;
/// The GlobalStrings key of catalog id `0x7e` — the row `NotWhileDeadError`'s pushed id resolves
/// to ("You can't do that when you're dead.").
const NOT_WHILE_DEAD_KEY: &str = "ERR_PLAYER_DEAD";
/// Register the error-display globals.
pub(super) fn install(lua: &Lua) -> mlua::Result<()> {
lua.globals().set(
"NotWhileDeadError",
lua.create_function(|lua, ()| {
let mut model = lua.app_data_mut::<Model>().expect("model app_data");
model.ui_errors.push(NOT_WHILE_DEAD_KEY);
Ok(())
})?,
)
}