Here's the in-game text string display proc.
It seems to be used for both player chat and game text messages.... "Work Complete" etc.
It's got 3 args:
CHAR * lpszString
INT player
INT display_time
if
player is a valid player number in the current game it will display the players name then a colon ':' then the message.
I think it's -1 for no player name (game message)?? I can't remember its been a while since I looked at this but its something like that.
most (all?) in game text is displayed for 7 seconds on the screen.
if the
display_time value is <1000 ( 1 second ) it will default to 7000 = usual 7 second display.
.text:0042CA40 ingame_display_string proc near
.text:0042CA40
.text:0042CA40 temp_str_buffer = byte ptr -200h
.text:0042CA40 lpString = dword ptr 4
.text:0042CA40 nPlayer = dword ptr 8
.text:0042CA40 display_time = dword ptr 0Ch
.text:0042CA40
.text:0042CA40 sub esp, 200h ; time<1000 = 7000
.text:0042CA46 push ebx
.text:0042CA47 push esi
.text:0042CA48 push edi
.text:0042CA49 mov edi, [esp+20Ch+lpString]
.text:0042CA50 test edi, edi
.text:0042CA52 jz loc_42CB43
.text:0042CA58 mov ebx, [esp+20Ch+display_time]
.text:0042CA5F cmp ebx, 3E8h ; 1000
.text:0042CA65 jnb short loc_42CA6C
.text:0042CA67 mov ebx, 1B58h ; 7000
.text:0042CA6C
.text:0042CA6C loc_42CA6C: ; CODE XREF: ingame_display_string+25j
.text:0042CA6C mov ecx, [esp+20Ch+nPlayer]
.text:0042CA73 mov eax, ecx
.text:0042CA75 and eax, 0FFh
.text:0042CA7A cmp eax, 0FFFFFFFFh
.text:0042CA7D jnz short loc_42CA9C
.text:0042CA7F or ecx, eax
.text:0042CA81 xor eax, eax
.text:0042CA83 repne scasb
.text:0042CA85 not ecx
.text:0042CA87 sub edi, ecx
.text:0042CA89 mov eax, ecx
.text:0042CA8B mov esi, edi
.text:0042CA8D mov edi, dword_4B3FB8
.text:0042CA93 shr ecx, 2
.text:0042CA96 rep movsd
.text:0042CA98 mov ecx, eax
.text:0042CA9A jmp short loc_42CABD
.text:0042CA9C ; ---------------------------------------------------------------------------
.text:0042CA9C
.text:0042CA9C loc_42CA9C: ; CODE XREF: ingame_display_string+3Dj
.text:0042CA9C cmp cl, 8
.text:0042CA9F jnz short loc_42CB06
.text:0042CAA1 or ecx, 0FFFFFFFFh
.text:0042CAA4 xor eax, eax
.text:0042CAA6 repne scasb
.text:0042CAA8 not ecx
.text:0042CAAA sub edi, ecx
.text:0042CAAC mov edx, ecx
.text:0042CAAE mov esi, edi
.text:0042CAB0 mov edi, dword_4B3FB8
.text:0042CAB6 shr ecx, 2
.text:0042CAB9 rep movsd
.text:0042CABB mov ecx, edx
.text:0042CABD
.text:0042CABD loc_42CABD: ; CODE XREF: ingame_display_string+5Aj
.text:0042CABD and ecx, 3
.text:0042CAC0 rep movsb
.text:0042CAC2 mov byte_4B3F44, 4
.text:0042CAC9 call GetTickCount
.text:0042CACE add eax, ebx
.text:0042CAD0 push 1CFh
.text:0042CAD5 mov dword_4B3F7C, eax
.text:0042CADA mov eax, dword_4B3F84
.text:0042CADF push 266h
.text:0042CAE4 lea eax, [eax+eax*2]
.text:0042CAE7 lea ecx, ds:0C2h[eax*4]
.text:0042CAEE push ecx
.text:0042CAEF push 0BAh
.text:0042CAF4 call sub_486260
.text:0042CAF9 add esp, 10h
.text:0042CAFC pop edi
.text:0042CAFD pop esi
.text:0042CAFE pop ebx
.text:0042CAFF add esp, 200h
.text:0042CB05 retn
.text:0042CB06 ; ---------------------------------------------------------------------------
.text:0042CB06
.text:0042CB06 loc_42CB06: ; CODE XREF: ingame_display_string+5Fj
.text:0042CB06 lea edx, ds:0[eax*8]
.text:0042CB0D push edi
.text:0042CB0E sub edx, eax
.text:0042CB10 lea ecx, [esp+210h+temp_str_buffer]
.text:0042CB14 lea eax, ds:4AD758h[edx*8]
.text:0042CB1B push eax ; char
.text:0042CB1C push offset aSS_0 ; "%s: %s"
.text:0042CB21 push 200h ; size_t
.text:0042CB26 push ecx ; char *
.text:0042CB27 call sub_489AA0
.text:0042CB2C call GetTickCount
.text:0042CB31 add eax, ebx
.text:0042CB33 lea edx, [esp+220h+temp_str_buffer]
.text:0042CB37 push eax
.text:0042CB38 push 2
.text:0042CB3A push edx
.text:0042CB3B call sub_42CB50
.text:0042CB40 add esp, 20h
.text:0042CB43
.text:0042CB43 loc_42CB43: ; CODE XREF: ingame_display_string+12j
.text:0042CB43 pop edi
.text:0042CB44 pop esi
.text:0042CB45 pop ebx
.text:0042CB46 add esp, 200h
.text:0042CB4C retn
.text:0042CB4C ingame_display_string endp
Perhaps this could be a starting point for porting chat to UNICODE, but there would be lots to check upstream from this.
The main issue is that wide chars very commonly have the second BYTE set to 0, which will of course terminate a standard C-style ANSI string, so quite possibly most messages could end up truncated after the first character by any routine that is handling them as standard zero-terminated ANSII strings.
hf
-- edit --
case in point - This:
.text:0042CA81 xor eax, eax
.text:0042CA83 repne scasb
searches a string for the first 0 BYTE it finds...