Commit graph

3 commits

Author SHA1 Message Date
Erik
e62aaebda0 feat(chat): CT-B2 — "/r " expands to a tell at whoever last told you
Campaign CT slice B2, and the autocomplete the user asked about directly.

Typing "/r " now rewrites the chat entry to "@tell {LastTeller}, " the moment
the space lands, matching ChatInterface::HandleTextReplacements @0x004F50D0 ->
SetReplyTextInChatBox @0x004F4760.

This is display sugar rather than routing: "/r hello" already SENT correctly
through ChatInputParser's reply aliases. What was missing is that the player
could not SEE who they were about to reply to before pressing enter.

The trigger strings came out of the constant pool, not the decompiled listing —
Binary Ninja renders them as bare data_* references with no preview:

    data_7C4C70 = "r "      data_7C4C68 = "rp "      data_7C4C58 = "reply "

Retail stores them WITHOUT the leading prefix and tests the first character
separately against '/' (0x2F) or '@' (0x40), which is why both prefixes work.
The research summary for this area listed the triggers as "/t ", "/tell " and
"reply " — reading the pool corrected that.

Three boundaries, each pinned by test because each is a way to get this subtly
wrong:

  - The trailing space is PART of the trigger. "/r" alone must be left alone —
    the player may still be typing "/roleplay", and expanding early would
    hijack a different command mid-word.
  - Only on space. Running the replacer per keystroke would rewrite text out
    from under someone mid-word; retail keys on 0x20 specifically.
  - Only with the caret at the end. Otherwise the player is editing existing
    text, and expanding would corrupt a sentence they are part way through
    fixing.

With nobody to reply to, nothing is rewritten — retail leaves the text alone
rather than producing a tell addressed to nobody, and the ordinary submit path
still reports "Someone must @tell you first!".

Solution builds clean; full hermetic gate green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:10:39 +02:00
Erik
10304f6dc2 fix(chat): announce enchantment expiry; stop double-printing tells
Two of the four reported chat defects.

**Only item spells announced their expiry.** ACE splits the two cases: an
enchantment expiring on an ITEM arrives as ordinary server chat ("The spell X
on Y has expired.") — which is why those were the only ones showing — while
one expiring on the PLAYER arrives as GameEventMagicDispelEnchantment carrying
no text at all, because retail's client writes that line itself.
ClientMagicSystem::NotifyOfEnchantmentRemoval @0x005686C0 is now ported: the
spell's own name plus " has expired.", at LogTextType 7 (Magic), including
retail's guards (ids >= 0x8000 skipped, a spell missing from the table prints
nothing) and its one special case — spell 0x29A gets " penalty" appended so
vitae reads "Vitae penalty has expired."

Retail's trailing "\n" is deliberately dropped: its scroll appends raw text,
AddText is line-based, and keeping it would print a blank line.

**Every tell printed twice.** ACE's GameActionTell replies with a
GameMessageSystemChat carrying the finished "You tell X, ..." line
(ChatMessageType.OutgoingTell), and we ALSO emitted an optimistic local echo.
Retail's own send path, Event_TalkDirectByName @0x00577CF4, has no
AddTextToScroll beside it — it just transmits and lets the server's reply
print. The local echo is removed, which also makes Tell consistent with Say,
which has always relied on the server echo.

CH3 had this half-right: it removed the legacy-channel echo for precisely this
reason, but kept the Tell echo on the stated grounds that "the server never
resends" it. That premise was false. Both test comments asserting it are
corrected rather than deleted, since the wrong claim is what made the bug
survive review.

Solution builds clean; 14,477 tests pass on the standard hermetic lane filter,
0 failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 06:11:33 +02:00
Erik
41b15efd4d feat(runtime): share chat commands and run login sequence 2026-08-14 20:27:45 +02:00