2828#include " vgui_parser.h"
2929#include " draw_util.h"
3030#include " com_weapons.h"
31+ #include " utlstring.h"
3132// #include "vgui_TeamFortressViewport.h"
3233
3334extern float *GetClientColor ( int clientIndex );
@@ -268,29 +269,23 @@ int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf )
268269{
269270 BufferReader reader ( pszName, pbuf, iSize );
270271 int client_index, argc, numArgs; // the client who spoke the message
271- char *arg, *fmt, *argv[3 ] = {};
272+ CUtlString fmt;
273+ CUtlString argv[3 ];
272274 const char *fmt_tran = nullptr ;
273275 bool allowDead, replaceFirstArgToName, swap;
274- int len;
275276
276277 client_index = reader.ReadByte ();
277278
278279 // find all arguments
279- arg = reader.ReadString ();
280- len = strlen ( arg );
281- fmt = new char [len+1 ];
282- strcpy (fmt, arg);
280+ fmt = reader.ReadString ();
283281
284282 for ( argc = 0 ; argc < 3 ; argc++ )
285283 {
286- arg = reader.ReadString ();
284+ const char * arg = reader.ReadString ();
287285 if ( !arg[0 ] && !reader.Valid () )
288286 break ;
289287
290- len = strlen ( arg );
291- argv[argc] = new char [len+1 ];
292- strncpy ( argv[argc], arg, len );
293- argv[argc][len] = 0 ;
288+ argv[argc] = arg;
294289 }
295290
296291 // see if argv[0] is translatable
@@ -317,68 +312,76 @@ int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf )
317312 // no translations
318313 if ( !fmt_tran )
319314 {
320- fmt_tran = fmt;
315+ fmt_tran = fmt. Get () ;
321316 numArgs = argc;
322317 allowDead = true ;
323318 replaceFirstArgToName = false ;
324319 swap = false ;
325320 }
326321
322+ // Convert indexed placeholders (%s1, %s2) to standard C-format (%s)
323+ // to ensure compatibility with snprintf below.
324+ CUtlString fmt_local = fmt_tran;
325+ Localize_StripIndices ( fmt_local.Access () );
326+
327327 // If text is sent from dead player or spectator
328328 // don't draw it, until local player isn't specator or dead.
329329 if ( !allowDead && !CL_IsDead () && !g_iUser1 )
330330 {
331- delete[] fmt;
331+ return 1 ;
332+ }
332333
333- for ( int i = 0 ; i < 3 ; i++ )
334- if ( argv[i] ) delete argv[i];
334+ bool nameArgReplaced = false ;
335335
336- return 1 ;
336+ // Resolve missing nickname locally via client_index mapping.
337+ if ( !replaceFirstArgToName && client_index > 0 && numArgs > 0 && argv[0 ].Length () == 0 )
338+ {
339+ GetPlayerInfo ( client_index, &g_PlayerInfoList[client_index] );
340+ argv[0 ] = g_PlayerInfoList[client_index].name ;
341+ nameArgReplaced = true ;
337342 }
338343
339344 if ( replaceFirstArgToName )
340345 {
341346 GetPlayerInfo ( client_index, &g_PlayerInfoList[client_index] );
342- delete[] argv[0 ];
343-
344347 argv[0 ] = g_PlayerInfoList[client_index].name ;
348+ nameArgReplaced = true ;
345349 }
346350
347- char dst[1024 ];
351+ // Strip indices from argument strings too (when not replaced by name)
352+ for ( int i = 0 ; i < numArgs; ++i )
353+ {
354+ if ( !(i == 0 && nameArgReplaced) )
355+ {
356+ Localize_StripIndices ( argv[i].Access () );
357+ }
358+ }
359+
360+ CUtlString dst;
361+ char tmp[1024 ];
348362
349363 switch ( numArgs )
350364 {
351365 case 3 :
352366 if ( swap )
353- snprintf ( dst , sizeof ( dst ), fmt_tran , argv[0 ], argv[2 ], argv[1 ] );
367+ snprintf ( tmp , sizeof ( tmp ), fmt_local. Get () , argv[0 ]. Get () , argv[2 ]. Get () , argv[1 ]. Get () );
354368 else
355- snprintf ( dst , sizeof ( dst ), fmt_tran , argv[0 ], argv[1 ], argv[2 ] );
369+ snprintf ( tmp , sizeof ( tmp ), fmt_local. Get () , argv[0 ]. Get () , argv[1 ]. Get () , argv[2 ]. Get () );
356370 break ;
357371 case 2 :
358- snprintf ( dst , sizeof ( dst ), fmt_tran , argv[0 ], argv[1 ] );
372+ snprintf ( tmp , sizeof ( tmp ), fmt_local. Get () , argv[0 ]. Get () , argv[1 ]. Get () );
359373 break ;
360374 case 1 :
361- snprintf ( dst , sizeof ( dst ), fmt_tran , argv[0 ] );
375+ snprintf ( tmp , sizeof ( tmp ), fmt_local. Get () , argv[0 ]. Get () );
362376 break ;
363377 case 0 :
364- strncpy ( dst, fmt_tran , sizeof ( dst ) );
365- dst [sizeof (dst )-1 ] = 0 ;
378+ strncpy ( tmp, fmt_local. Get () , sizeof ( tmp ) );
379+ tmp [sizeof (tmp )-1 ] = 0 ;
366380 break ;
367381 }
368382
369- SayTextPrint ( dst, strlen (dst), client_index );
370-
371- delete[] fmt;
372-
373- for ( int i = 0 ; i < argc; i++ )
374- {
375- // skip second argument if it was replaced by name
376- if ( i == 0 && replaceFirstArgToName )
377- continue ;
378-
379- if ( argv[i] )
380- delete[] argv[i];
381- }
383+ dst = tmp;
384+ SayTextPrint ( dst.Get (), dst.Length (), client_index );
382385
383386 return 1 ;
384387}
0 commit comments