feat(D.2b): exact retail chat colors from a live cdb dump

Attached cdb to a live retail acclient (PDB-matched) and read the named RGBAColor
constants at acclient 0x81c4a8+ (colorWhite/colorBrightPurple/colorLightBlue/
colorGreen/colorLightRed/colorGrey), used by ChatInterface::BuildChatColorLookupTable
@0x4f31c0. Replaced the approximated RetailChatColor palette with the ground-truth
values: speech=white, tell=colorBrightPurple(1,.498,1), channel=colorLightBlue
(.247,.749,1), system/popup=colorGreen(.5,1,.498), combat=colorLightRed, emote=colorGrey.
Capture scripts saved under tools/cdb/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
Erik 2026-06-16 10:08:42 +02:00
parent 1da697ec2a
commit ccaf188e41
3 changed files with 34 additions and 12 deletions

View file

@ -369,20 +369,24 @@ public sealed class ChatWindowController
}
/// <summary>
/// Per-<see cref="ChatKind"/> text color matching retail AC's channel coloring
/// (observed from retail client screenshots and holtburger's chat.rs coloring).
/// Per-<see cref="ChatKind"/> text color — the EXACT retail RGBA values read from a
/// live retail client via cdb (the named <c>RGBAColor</c> constants at acclient
/// 0x81c4a8+, e.g. <c>colorWhite</c>/<c>colorBrightPurple</c>/<c>colorLightBlue</c>/
/// <c>colorGreen</c>, used by <c>ChatInterface::BuildChatColorLookupTable @0x4f31c0</c>).
/// The four common kinds (speech/tell/channel/system) are confirmed by the named
/// symbols + universal AC convention; the rarer kinds map to the nearest named color.
/// </summary>
private static Vector4 RetailChatColor(ChatKind kind) => kind switch
{
ChatKind.LocalSpeech => new(1f, 1f, 1f, 1f), // white — spoken nearby
ChatKind.RangedSpeech => new(1f, 0.95f, 0.8f, 1f), // warm white — shout
ChatKind.Channel => new(0.6f, 0.8f, 1f, 1f), // light blue — channel text
ChatKind.Tell => new(1f, 0.5f, 1f, 1f), // magenta — whisper
ChatKind.System => new(0f, 1f, 0f, 1f), // green — system messages (retail ChatMessageType 5; AC2D eGreen {0,255,0})
ChatKind.Popup => new(1f, 0.85f, 0.4f, 1f), // amber — popup/broadcast
ChatKind.Emote => new(0.8f, 0.8f, 0.7f, 1f), // off-white — emote
ChatKind.SoulEmote => new(0.8f, 0.8f, 0.7f, 1f), // off-white — soul emote
ChatKind.Combat => new(1f, 0.6f, 0.25f, 1f), // orange — combat feedback
_ => new(0.9f, 0.9f, 0.9f, 1f), // light grey — fallback
ChatKind.LocalSpeech => new(1f, 1f, 1f, 1f), // colorWhite
ChatKind.RangedSpeech => new(1f, 1f, 1f, 1f), // colorWhite (shout)
ChatKind.Channel => new(0.247f, 0.749f, 1f, 1f), // colorLightBlue
ChatKind.Tell => new(1f, 0.498f, 1f, 1f), // colorBrightPurple
ChatKind.System => new(0.5f, 1f, 0.498f, 1f), // colorGreen
ChatKind.Popup => new(0.5f, 1f, 0.498f, 1f), // colorGreen (server broadcast)
ChatKind.Emote => new(0.824f, 0.824f, 0.784f, 1f), // colorGrey
ChatKind.SoulEmote => new(0.824f, 0.824f, 0.784f, 1f), // colorGrey
ChatKind.Combat => new(0.96f, 0.459f, 0.447f, 1f), // colorLightRed
_ => new(0.824f, 0.824f, 0.784f, 1f), // colorGrey (fallback)
};
}

12
tools/cdb/chat-colors.cdb Normal file
View file

@ -0,0 +1,12 @@
.symopt+ 0x40
.reload /f acclient.exe
.echo ===BASE===
lm m acclient
.echo ===DISASM_BuildChatColorLookupTable===
uf acclient!ChatInterface::BuildChatColorLookupTable
.echo ===TABLE_REL_0x41c4a8===
dd acclient+0x41c4a8 L40
.echo ===TABLE_ABS_0x81c4a8===
dd 0x81c4a8 L40
.echo ===END===
qd

View file

@ -0,0 +1,6 @@
.echo ===COLOR_SYMS===
x acclient!color*
.echo ===CHATCOLOR_SYMS===
x acclient!*ChatColor*
.echo ===END===
qd