acdream/src/AcDream.Core/Chat
Erik 35454a9f58 fix #436: combat no-target refusal reaches the SpewBox with retail's exact text
Attacking with no valid target has told the player nothing since Campaign V
slice V11 orphaned the DebugVM toast the message was wired to (#434 found
the drop; this closes it retail-faithfully).

Ground truth from the Ghidra decompile of
ClientCombatSystem::ExecuteAttack (0x0056bb70): retail writes
"You must select a valid combat target before attacking" via
ClientSystem::AddTextToScroll(..., 0x1A, true, 0) — the ClientLocal
SpewBox channel this codebase already routes every other client-local
refusal through. And retail has ONE message, not the two we carried:
attacking outside melee/missile modes is silent (ExecuteAttack is
unreachable there), so the invented "Enter melee or missile combat first"
text is deleted rather than rerouted, and the invented "No monster
target" is replaced by the retail string, which joins ClientTextRefusals
with its decomp citation.

Wiring: CombatFeedbackSlot gains the sibling BindOwned session-lifetime
shape, and SessionPlayerComposition.CompleteSessionPlayer binds it to
RuntimeCommunicationState.AddText(ClientLocal) with session-owned
teardown — a torn-down session's slot returns to its silent unbound
state. A binding-seam test
(CompleteSessionPlayerBindsCombatFeedbackToTheClientLocalSpewBoxRoute)
inspects the compiled composition for the BindOwned call and its
AddText-routing lambda, so the slot can never again pass its unit tests
while production leaves it unbound — the exact failure mode that hid
this defect. The two tests that pinned the invented strings now pin the
retail contract (exact string; silence for the unsupported-mode case).

Full hermetic suite 15,325 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 12:53:11 +02:00
..
ChatChannelInfo.cs fix(chat): CH3 review fixes — phantom UN-9, allegiance-broadcast echo, /a legacy fallback 2026-08-09 20:24:29 +02:00
ChatCommandTargetState.cs refactor(runtime): close canonical gameplay ownership 2026-07-26 09:48:51 +02:00
ChatLog.cs chore(chat): CT-D1/D2 — delete the dead ChatPanel, reconcile the stale digest 2026-08-21 10:27:43 +02:00
ChatSessionLog.cs feat(chat): CT-B4 — @log, and the research block that was a wrong question 2026-08-21 11:28:20 +02:00
ChatTagMarkup.cs feat(chat): CT-C2 Escape leaves the entry; CT-C3 the timestamp is grey 2026-08-21 08:28:45 +02:00
ChatWindowState.cs feat(ui): Campaign OP slice OP5 — the Chat tab 2026-08-11 06:25:59 +02:00
ClientTextRefusals.cs fix #436: combat no-target refusal reaches the SpewBox with retail's exact text 2026-08-24 12:53:11 +02:00
CombatChatTranslator.cs fix(chat): CH1 review fixes — sbb-idiom channel catch-all, command-output typing 2026-08-09 16:03:13 +02:00
InventoryFailureMessages.cs fix: social gate round 2, part 2 - confirmation-dialog sentences + the 2026-08-13 21:10:42 +02:00
LegacyChannelChatType.cs fix(chat): CH1 review fixes — sbb-idiom channel catch-all, command-output typing 2026-08-09 16:03:13 +02:00
OptionsPanelText.cs feat(ui): Campaign OP slice OP3 — Options panel shell, open paths, Gameplay tab 2026-08-11 02:14:40 +02:00
RetailLogTextType.cs fix(chat): CH1 review fixes — sbb-idiom channel catch-all, command-output typing 2026-08-09 16:03:13 +02:00
SpewBoxState.cs fix(chat): CH2 re-review nits — resize centering, top-aligned flow, sweep wording 2026-08-09 18:48:13 +02:00
TurbineChatState.cs refactor(net): converge live session state reset 2026-07-21 12:00:48 +02:00
WeenieErrorMessages.cs fix(chat): FA1 -- 8 fellowship WeenieError ids confirmed absent from retail, not missing 2026-08-12 00:13:25 +02:00