feat(chat): the talk-focus menu's Tell-to / Squelch entries actually work
Both entries were deliberate no-ops — the code said so — and both showed a static label where retail shows the selected player's NAME. Retail builds them in gmMainChatUI::InitTalkFocusMenu @0x004CDC50 and rebuilds their labels every time the menu opens, substituting the selection through StringInfo::AddVariable_String (@0x004CD91C / @0x004CD982). So they now read "Tell to Dww" / "Squelch (ignore) Dww", rebuilt on open from a live selection provider, and grey out with nothing selected — retail arms the tell slot only for a talkable target (SetTalkFocusEnabled(2, 1) @0x004CD9B0). Picking "Tell to X" aims the chat bar at X. That needed one piece of plumbing: the parser's plain-speech fallthrough returned a null target, so a line typed under a Tell focus was dropped by the router for having no one to send to. Parse/Submit now carry an optional default tell target for exactly that case. "Squelch X" publishes the ALREADY-REGISTERED /squelch verb rather than reimplementing the request — the ModifyCharacterSquelch wire builder (CM_Communication::Event_ModifyCharacterSquelch @0x006A42D0) has been there all along; only the menu path to it was missing. UiMenu gains an OnOpen seam, because a menu whose Items are fixed at Bind can only ever say "Tell to Selected". It fires before _open flips so the rebuilt rows are measured and drawn in the same opening. Solution builds clean; 14,480 tests pass on the standard hermetic lane filter, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
10304f6dc2
commit
581a61ef0c
6 changed files with 209 additions and 17 deletions
|
|
@ -28,6 +28,17 @@ public sealed class UiMenu : UiElement
|
|||
/// <summary>Fired with the picked item's payload when a row is chosen.</summary>
|
||||
public Action<object?>? OnSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Raised as the popup opens, before the rows are measured or drawn.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Retail rebuilds the talk-focus menu's two selection-dependent entries
|
||||
/// each time it opens (gmMainChatUI @0x004CD8E9), so their labels track
|
||||
/// whoever is selected right now. A menu whose Items were fixed at Bind
|
||||
/// could only ever say "Tell to Selected".
|
||||
/// </remarks>
|
||||
public Action? OnOpen { get; set; }
|
||||
|
||||
/// <summary>Per-payload enabled gate (disabled rows render greyed + are inert). Null ⇒ all enabled.</summary>
|
||||
public Func<object?, bool>? EnabledProvider { get; set; }
|
||||
|
||||
|
|
@ -258,6 +269,9 @@ public sealed class UiMenu : UiElement
|
|||
private void SetOpen(bool value)
|
||||
{
|
||||
if (_open == value) return;
|
||||
// Before _open flips, so a handler that replaces Items is reflected in
|
||||
// the very first measure/draw of this opening.
|
||||
if (value) OnOpen?.Invoke();
|
||||
_open = value;
|
||||
if (FindRoot() is not { } root) return;
|
||||
if (value) root.SetActivePopup(this, () => SetOpen(false));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue