fix(chat): #363 — retail 0x1A typing for command refusals via the interface-text seam
ChatVM gains an OnInterfaceText hook + ShowInterfaceText(text), the
App-layer composition wires it to RuntimeCommunicationState.AddText,
and ChatCommandRouter routes every retail-0x1A command refusal through
it instead of the chat log's 0x00 sink. UI.Abstractions still never
references Runtime directly; unwired hosts (headless, tests) fall back
to the chat log tagged ClientLocal so no text is ever silently lost.
Reclassified per register row AP-183 (DoChannelList/On/Off, DoAllegiance,
DoHouseAvailableList — the last also corrected to retail's own bad-house-
type string instead of a synthesized "Usage:" line) and newly wired two
sites that previously showed nothing at all (DoStupidChannelHack's bare
legacy-channel-verb refusal, DoReply's message-but-no-last-teller
refusal). The generic bad-args fallback now resolves WeenieErrorMessages
0x026 ("That is not a valid command.", retail's HandleFailureEvent(0x26))
instead of synthesizing "Usage: {Usage}". DoSpeaker/DoEndurance/DoTitle
are untouched — already correct at 0x00.
Also closes #367 (DoHelp's "Unknown command" fallback and the degenerate-
prefix refusal now reach the SpewBox too) and retires register row
AP-186, whose own filing proposed exactly this seam shape.
Full Release suite: 12,542 passed / 4 skipped / 0 failed (baseline
12,466/4/0 at ff2784ea).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff2784eaa4
commit
09453ecae8
14 changed files with 702 additions and 106 deletions
|
|
@ -124,6 +124,64 @@ public static class ChatInputParser
|
|||
("/o", ChatChannelKind.Olthoi),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The six retail channel groups whose registered-verb handler is
|
||||
/// <c>ClientCommunicationSystem::DoStupidChannelHack @0x0057B144</c>
|
||||
/// (command-registry doc §2.3) — the legacy 0x0147 channels. The
|
||||
/// Turbine-only channels (General/Trade/Lfg/Roleplay/Society/Olthoi)
|
||||
/// are never this handler's clients. <see cref="ChatChannelKind.Allegiance"/>
|
||||
/// (retail's <c>@a</c>) still belongs here even though acdream always
|
||||
/// sends it over Turbine once connected (<see cref="ChatChannelKind"/>'s
|
||||
/// own doc comment) — DoStupidChannelHack dispatches on the REGISTERED
|
||||
/// VERB, before Turbine send-time routing decides where the text goes;
|
||||
/// retail's <c>"a"</c>/<c>"ab"</c> are one registered verb group.
|
||||
/// </summary>
|
||||
private static readonly HashSet<ChatChannelKind> LegacyChannelHackKinds =
|
||||
[
|
||||
ChatChannelKind.Fellowship,
|
||||
ChatChannelKind.Allegiance,
|
||||
ChatChannelKind.AllegianceBroadcast,
|
||||
ChatChannelKind.Vassals,
|
||||
ChatChannelKind.Patron,
|
||||
ChatChannelKind.Monarch,
|
||||
ChatChannelKind.CoVassals,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// True when <paramref name="trimmed"/> is one of the
|
||||
/// <see cref="LegacyChannelHackKinds"/> verbs with NO message — retail's
|
||||
/// <c>DoStupidChannelHack</c> "You must specify the text you wish to
|
||||
/// say!" refusal (<c>0x1A</c> ClientLocal,
|
||||
/// acclient_2013_pseudo_c.txt:1030730, data_7da9b0). This parser stays
|
||||
/// pure (no side effects — <see cref="Parse"/> just returns
|
||||
/// <see langword="null"/> for this shape); <see cref="ChatCommandRouter"/>
|
||||
/// owns the actual refusal text and routes it to the SpewBox.
|
||||
/// </summary>
|
||||
public static bool IsBareRegisteredChannelVerb(string trimmed)
|
||||
{
|
||||
foreach (var (verb, channel) in ChannelVerbs)
|
||||
{
|
||||
if (LegacyChannelHackKinds.Contains(channel) && IsBareVerb(trimmed, [verb]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True when <paramref name="trimmed"/> is <c>/reply</c>/<c>/r</c>/
|
||||
/// <c>/rp</c> WITH a message but no prior incoming Tell — retail's
|
||||
/// <c>ClientCommunicationSystem::DoReply @0x00577910</c> "Someone must
|
||||
/// @tell you first!" refusal (<c>0x1A</c> ClientLocal,
|
||||
/// acclient_2013_pseudo_c.txt:387538, data_7da974), the
|
||||
/// <c>gmCCommunicationSystem::GetLastTeller() == 0</c> branch. Bare
|
||||
/// <c>/r</c> with no message at all is a DIFFERENT retail branch (its
|
||||
/// own copy of the "you must specify text" string) and is deliberately
|
||||
/// out of scope here — not named by register row AP-183 / issue #363.
|
||||
/// </summary>
|
||||
public static bool IsReplyMissingLastTeller(string trimmed, string? lastTellSender) =>
|
||||
string.IsNullOrEmpty(lastTellSender) && TryParseMessageOnly(trimmed, ReplyAliases, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Parse <paramref name="raw"/> into a <see cref="ParsedInput"/>
|
||||
/// triple, or <c>null</c> if the input is empty / whitespace /
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue