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
|
|
@ -31,7 +31,8 @@ public static class ChatCommandRouter
|
|||
string? raw,
|
||||
IChatCommandFeedback feedback,
|
||||
ICommandBus bus,
|
||||
ChatChannelKind defaultChannel)
|
||||
ChatChannelKind defaultChannel,
|
||||
string? defaultTellTarget = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(feedback);
|
||||
ArgumentNullException.ThrowIfNull(bus);
|
||||
|
|
@ -166,7 +167,8 @@ public static class ChatCommandRouter
|
|||
trimmed,
|
||||
defaultChannel,
|
||||
feedback.LastIncomingTellSender,
|
||||
feedback.LastOutgoingTellTarget);
|
||||
feedback.LastOutgoingTellTarget,
|
||||
defaultTellTarget);
|
||||
if (parsed is { } chat)
|
||||
{
|
||||
bus.Publish(new SendChatCmd(chat.Channel, chat.TargetName, chat.Text));
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ public static class ChatInputParser
|
|||
string raw,
|
||||
ChatChannelKind defaultChannel,
|
||||
string? lastTellSender,
|
||||
string? lastOutgoingTellTarget = null)
|
||||
string? lastOutgoingTellTarget = null,
|
||||
string? defaultTellTarget = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw)) return null;
|
||||
var trimmed = raw.Trim();
|
||||
|
|
@ -219,7 +220,12 @@ public static class ChatInputParser
|
|||
string verb = ExtractVerb(substituted);
|
||||
if (IsKnownVerb(verb))
|
||||
{
|
||||
return Parse(substituted, defaultChannel, lastTellSender, lastOutgoingTellTarget);
|
||||
return Parse(
|
||||
substituted,
|
||||
defaultChannel,
|
||||
lastTellSender,
|
||||
lastOutgoingTellTarget,
|
||||
defaultTellTarget);
|
||||
}
|
||||
// Unknown @-verb — keep the original @ so ACE recognizes
|
||||
// it server-side. Always emit as Say: ACE's GameActionTalk
|
||||
|
|
@ -281,6 +287,19 @@ public static class ChatInputParser
|
|||
|
||||
// Plain speech (no recognized verb): emit on the default channel
|
||||
// so the user's text round-trips instead of being silently dropped.
|
||||
//
|
||||
// A Tell focus needs a target to go with it. Retail's talk-focus menu
|
||||
// aims the chat bar at the SELECTED player
|
||||
// (gmMainChatUI::InitTalkFocusMenu -> SetTalkFocusEnabled(2, 1)
|
||||
// @0x004CD9B0), and without that name a plain line typed under a Tell
|
||||
// focus is dropped by the router for having no target.
|
||||
if (defaultChannel == ChatChannelKind.Tell)
|
||||
{
|
||||
return string.IsNullOrEmpty(defaultTellTarget)
|
||||
? null
|
||||
: new ParsedInput(ChatChannelKind.Tell, defaultTellTarget, trimmed);
|
||||
}
|
||||
|
||||
return new ParsedInput(defaultChannel, null, trimmed);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue