void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) { int i; // find an empty string slot for ( i = 0; i < MAX_LINES; i++ ) { if ( ! *g_szLineBuffer[i] ) break; } if ( i == MAX_LINES ) { // force scroll buffer up ScrollTextUp(); i = MAX_LINES - 1; } g_iNameLengths[i] = 0; g_pflNameColors[i] = NULL; // if it's a say message, search for the players name in the string if ( *pszBuf == 2 && clientIndex > 0 ) { GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); const char *pName = g_PlayerInfoList[clientIndex].name; if ( pName ) { const char *nameInString = strstr( pszBuf, pName ); if ( nameInString ) { g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); g_pflNameColors[i] = GetClientColor( clientIndex ); } } } strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); // make sure the text fits in one line EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); // Set scroll time if ( i == 0 ) { flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; } m_iFlags |= HUD_ACTIVE; PlaySound( "misc/talk.wav", 1 ); if ( ScreenHeight >= 480 ) Y_START = ScreenHeight - 60; else Y_START = ScreenHeight - 45; Y_START -= (line_height * (MAX_LINES+1)); }
void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) { int line_width = 0; GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) { // string is too long to fit on line // scan the string until we find what word is too long, and wrap the end of the sentence after the word int length = LINE_START; int tmp_len = 0; char *last_break = NULL; for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) { // check for a color change, if so skip past it if ( x[0] == '/' && x[1] == '(' ) { x += 2; // skip forward until past mode specifier while ( *x != 0 && *x != ')' ) x++; if ( *x != 0 ) x++; if ( *x == 0 ) break; } char buf[2]; buf[1] = 0; if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character last_break = x; buf[0] = *x; // get the length of the current character GetConsoleStringSize( buf, &tmp_len, &line_height ); length += tmp_len; if ( length > MAX_LINE_WIDTH ) { // needs to be broken up if ( !last_break ) last_break = x-1; x = last_break; // find an empty string slot int j; do { for ( j = 0; j < MAX_LINES; j++ ) { if ( ! *g_szLineBuffer[j] ) break; } if ( j == MAX_LINES ) { // need to make more room to display text, scroll stuff up then fix the pointers int linesmoved = ScrollTextUp(); line -= linesmoved; last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); } } while ( j == MAX_LINES ); // copy remaining string into next buffer, making sure it starts with a space character if ( (char)*last_break == (char)' ' ) { int linelen = strlen(g_szLineBuffer[j]); int remaininglen = strlen(last_break); if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) strcat( g_szLineBuffer[j], last_break ); } else { if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) { strcat( g_szLineBuffer[j], " " ); strcat( g_szLineBuffer[j], last_break ); } } *last_break = 0; // cut off the last string EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); break; } } } }
void CHudSayText :: SayTextPrint( const char *pszBuf, size_t uiBufSize, int clientIndex ) { if ( gViewPort && !gViewPort->AllowedToPrintText() ) { // Print it straight to the console ConsolePrint( pszBuf ); return; } int i; // find an empty string slot for ( i = 0; i < MAX_LINES; i++ ) { if ( ! *m_szLineBuffer[i] ) break; } if ( i == MAX_LINES ) { // force scroll buffer up ScrollTextUp(); i = MAX_LINES - 1; } m_iNameLengths[i] = 0; m_pvecNameColors[i] = nullptr; // if it's a say message, search for the players name in the string if ( *pszBuf == 2 && clientIndex > 0 ) { gEngfuncs.pfnGetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); const char *pName = g_PlayerInfoList[clientIndex].name; if ( pName ) { const char *nameInString = strstr( pszBuf, pName ); if ( nameInString ) { m_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); m_pvecNameColors[i] = &GetClientColor( clientIndex ); } } } //Need to assign the constant to a local here because std::max takes it by reference, which won't work for this constant. //Static const integrals initialized in their declaration have no address, which causes segfaults on Linux. //See https://www.reddit.com/r/cpp_questions/comments/510sdc/strange_segfault_under_gcc_using_stdmax_and // - Solokiller const size_t uiMax = MAX_CHARS_PER_LINE; strncpy( m_szLineBuffer[i], pszBuf, max(uiBufSize , uiMax ) ); // make sure the text fits in one line EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); // Set scroll time if ( i == 0 ) { m_flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; } m_iFlags |= HUD_ACTIVE; PlaySound( "misc/talk.wav", 1 ); m_iYStart = ScreenHeight - 60 - ( m_iLineHeight * (MAX_LINES+2) ); }