//----------------------------------------------------------------------------- // Purpose: Text chat input/output hud element //----------------------------------------------------------------------------- CBaseHudChat::CBaseHudChat( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudChat" ) { vgui::Panel *pParent = g_pClientMode->GetViewport(); SetParent( pParent ); vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme"); SetScheme(scheme); m_nMessageMode = 0; CBaseHudChatLine *line = m_ChatLines[ 0 ]; if ( line ) { vgui::HFont font = line->GetFont(); m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2; // Put input area at bottom int w, h; GetSize( w, h ); m_pChatInput->SetBounds( 1, h - m_iFontHeight - 1, w-2, m_iFontHeight ); } if ( IsPC() ) { vgui::ivgui()->AddTickSignal( GetVPanel() ); } // (We don't actually want input until they bring up the chat line). MakePopup(); SetZPos( -30 ); SetHiddenBits( HIDEHUD_CHAT ); }
//----------------------------------------------------------------------------- // Purpose: // Input : width - // *text - // textlen - // Output : int //----------------------------------------------------------------------------- int CBaseHudChat::ComputeBreakChar( int width, const char *text, int textlen ) { #ifndef _XBOX CBaseHudChatLine *line = m_ChatLine; vgui::HFont font = line->GetFont(); int currentlen = 0; int lastbreak = textlen; for (int i = 0; i < textlen ; i++) { char ch = text[i]; if ( ch <= 32 ) { lastbreak = i; } wchar_t wch[2]; g_pVGuiLocalize->ConvertANSIToUnicode( &ch, wch, sizeof( wch ) ); int a,b,c; vgui::surface()->GetCharABCwide(font, wch[0], a, b, c); currentlen += a + b + c; if ( currentlen >= width ) { // If we haven't found a whitespace char to break on before getting // to the end, but it's still too long, break on the character just before // this one if ( lastbreak == textlen ) { lastbreak = max( 0, i - 1 ); } break; } } if ( currentlen >= width ) { return lastbreak; } return textlen; #else return 0; #endif }
//----------------------------------------------------------------------------- // Purpose: // Output : CBaseHudChatLine //----------------------------------------------------------------------------- CBaseHudChatLine *CBaseHudChat::FindUnusedChatLine( void ) { #ifndef _XBOX for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) { CBaseHudChatLine *line = m_ChatLines[ i ]; if ( !line ) continue; if ( line->IsVisible() ) continue; return line; } return NULL; #else return NULL; #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseHudChat::Clear( void ) { #ifndef _XBOX // Kill input prompt StopMessageMode(); // Expire all messages for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) { CBaseHudChatLine *line = m_ChatLines[ i ]; if ( !line ) continue; if ( !line->IsVisible() ) continue; line->Expire(); } #endif }
//----------------------------------------------------------------------------- // Purpose: Do respositioning here to avoid latency due to repositioning of vgui // voice manager icon panel //----------------------------------------------------------------------------- void CBaseHudChat::OnTick( void ) { #ifndef _XBOX m_nVisibleHeight = 0; CBaseHudChatLine *line = m_ChatLine; if ( line ) { vgui::HFont font = line->GetFont(); m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2; // Put input area at bottom int iChatX, iChatY, iChatW, iChatH; int iInputX, iInputY, iInputW, iInputH; m_pChatInput->GetBounds( iInputX, iInputY, iInputW, iInputH ); GetBounds( iChatX, iChatY, iChatW, iChatH ); m_pChatInput->SetBounds( iInputX, iChatH - (m_iFontHeight * 1.75), iInputW, m_iFontHeight ); //Resize the History Panel so it fits more lines depending on the screen resolution. int iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH; GetChatHistory()->GetBounds( iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH ); iChatHistoryH = (iChatH - (m_iFontHeight * 2.25)) - iChatHistoryY; GetChatHistory()->SetBounds( iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH ); } FadeChatHistory(); #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseHudChat::ExpireOldest( void ) { #ifndef _XBOX float oldestTime = 100000000.0f; CBaseHudChatLine *oldest = NULL; for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ ) { CBaseHudChatLine *line = m_ChatLines[ i ]; if ( !line ) continue; if ( !line->IsVisible() ) continue; if ( !oldest ) { oldest = line; oldestTime = line->GetStartTime(); continue; } if ( line->GetStartTime() < oldestTime ) { oldest = line; oldestTime = line->GetStartTime(); } } if ( !oldest ) { oldest = m_ChatLines[ 0 ]; } oldest->Expire(); #endif }
//----------------------------------------------------------------------------- // Purpose: // Input : *fmt - // ... - //----------------------------------------------------------------------------- void CBaseHudChat::ChatPrintf( int iPlayerIndex, int iFilter, const char *fmt, ... ) { va_list marker; char msg[4096]; va_start(marker, fmt); Q_vsnprintf(msg, sizeof( msg), fmt, marker); va_end(marker); // Strip any trailing '\n' if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' ) { msg[ strlen( msg ) - 1 ] = 0; } // Strip leading \n characters ( or notify/color signifiers ) for empty string check char *pmsg = msg; while ( *pmsg && ( *pmsg == '\n' || ( *pmsg > 0 && *pmsg < COLOR_MAX ) ) ) { pmsg++; } if ( !*pmsg ) return; // Now strip just newlines, since we want the color info for printing pmsg = msg; while ( *pmsg && ( *pmsg == '\n' ) ) { pmsg++; } if ( !*pmsg ) return; CBaseHudChatLine *line = (CBaseHudChatLine *)FindUnusedChatLine(); if ( !line ) { line = (CBaseHudChatLine *)FindUnusedChatLine(); } if ( !line ) { return; } if ( iFilter != CHAT_FILTER_NONE ) { if ( !(iFilter & m_iFilterFlags ) ) return; } if ( *pmsg < 32 ) { hudlcd->AddChatLine( pmsg + 1 ); } else { hudlcd->AddChatLine( pmsg ); } line->SetText( "" ); int iNameStart = 0; int iNameLength = 0; player_info_t sPlayerInfo; if ( iPlayerIndex == 0 ) { Q_memset( &sPlayerInfo, 0, sizeof(player_info_t) ); Q_strncpy( sPlayerInfo.name, "Console", sizeof(sPlayerInfo.name) ); } else { engine->GetPlayerInfo( iPlayerIndex, &sPlayerInfo ); } int bufSize = (strlen( pmsg ) + 1 ) * sizeof(wchar_t); wchar_t *wbuf = static_cast<wchar_t *>( _alloca( bufSize ) ); if ( wbuf ) { Color clrNameColor = GetClientColor( iPlayerIndex ); line->SetExpireTime(); g_pVGuiLocalize->ConvertANSIToUnicode( pmsg, wbuf, bufSize); // find the player's name in the unicode string, in case there is no color markup const char *pName = sPlayerInfo.name; if ( pName ) { wchar_t wideName[MAX_PLAYER_NAME_LENGTH]; g_pVGuiLocalize->ConvertANSIToUnicode( pName, wideName, sizeof( wideName ) ); const wchar_t *nameInString = wcsstr( wbuf, wideName ); if ( nameInString ) { iNameStart = (nameInString - wbuf); iNameLength = wcslen( wideName ); } } line->SetVisible( false ); line->SetNameStart( iNameStart ); line->SetNameLength( iNameLength ); line->SetNameColor( clrNameColor ); line->InsertAndColorizeText( wbuf, iPlayerIndex ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : *fmt - // ... - //----------------------------------------------------------------------------- void CBaseHudChat::Printf( const char *fmt, ... ) { #ifndef _XBOX // No chat text in single player if ( gpGlobals->maxClients == 1 ) { return; } va_list marker; char msg[4096]; const char *pTranslatedFmt = hudtextmessage->LookupString(fmt); va_start(marker, fmt); Q_vsnprintf( msg, sizeof( msg ), pTranslatedFmt, marker ); va_end(marker); // Strip any trailing '\n' if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' ) { msg[ strlen( msg ) - 1 ] = 0; } // Strip leading \n characters ( or notify/color signifiers ) char *pmsg = msg; while ( *pmsg && ( *pmsg == '\n' || *pmsg == 1 || *pmsg == 2 ) ) { pmsg++; } if ( !*pmsg ) return; // Search for return characters char *pos = strstr( pmsg, "\n" ); if ( pos ) { char msgcopy[ 8192 ]; Q_strncpy( msgcopy, pmsg, sizeof( msgcopy ) ); int offset = pos - pmsg; // Terminate first part msgcopy[ offset ] = 0; // Print first part #if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo Printf( "%s", msgcopy ); // Print remainder Printf( "%s", &msgcopy[ offset ] + 1 ); #else Printf( msgcopy ); // Print remainder Printf( &msgcopy[ offset ] + 1 ); #endif return; } CBaseHudChatLine *firstline = m_ChatLines[ 0 ]; int len = strlen( pmsg ); // Check for string too long and split into multiple lines // int breakpos = ComputeBreakChar( firstline->GetWide() - 10, pmsg, len ); if ( breakpos > 0 && breakpos < len ) { char msgcopy[ 8192 ]; Q_strncpy( msgcopy, pmsg, sizeof( msgcopy ) ); int offset = breakpos; char savechar; savechar = msgcopy[ offset ]; // Terminate first part msgcopy[ offset ] = 0; // Print first part #if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo Printf( "%s", msgcopy ); #else Printf( msgcopy ); #endif // Was breakpos a printable char? if ( savechar > 32 ) { msgcopy[ offset ] = savechar; // Print remainder #if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo Printf( "%s", &msgcopy[ offset ] ); #else Printf( &msgcopy[ offset ] ); #endif } else { #if defined( CSTRIKE_DLL ) || defined( DOD_DLL ) // reltodo Printf( "%s", &msgcopy[ offset ] + 1 ); #else Printf( &msgcopy[ offset ] + 1 ); #endif } return; } CBaseHudChatLine *line = FindUnusedChatLine(); if ( !line ) { ExpireOldest(); line = FindUnusedChatLine(); } if ( !line ) { return; } line->SetText( "" ); line->InsertColorChange( line->GetTextColor() ); line->SetExpireTime(); line->InsertString( pmsg ); line->SetVisible( true ); line->SetNameLength( 0 ); CLocalPlayerFilter filter; C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HudChat.Message" ); #endif }
//----------------------------------------------------------------------------- // Purpose: Do respositioning here to avoid latency due to repositioning of vgui // voice manager icon panel //----------------------------------------------------------------------------- void CBaseHudChat::OnTick( void ) { #ifndef _XBOX int i; for ( i = 0; i < CHAT_INTERFACE_LINES; i++ ) { CBaseHudChatLine *line = m_ChatLines[ i ]; if ( !line ) continue; if ( !line->IsVisible() ) continue; if ( !line->IsReadyToExpire() ) continue; line->Expire(); } int w, h; GetSize( w, h ); CBaseHudChatLine *line = m_ChatLines[ 0 ]; if ( line ) { vgui::HFont font = line->GetFont(); if ( font ) { m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2; // Put input area at bottom int w, h; GetSize( w, h ); m_pChatInput->SetBounds( 1, h - m_iFontHeight - 1, w-2, m_iFontHeight ); } } // Sort chat lines qsort( m_ChatLines, CHAT_INTERFACE_LINES, sizeof( CBaseHudChatLine * ), SortLines ); // Step backward from bottom int currentY = h - m_iFontHeight - 1; int startY = currentY; int ystep = m_iFontHeight; currentY -= GetChatInputOffset(); // Walk backward for ( i = CHAT_INTERFACE_LINES - 1; i >= 0 ; i-- ) { CBaseHudChatLine *line = m_ChatLines[ i ]; if ( !line ) continue; if ( !line->IsVisible() ) { line->SetSize( w, m_iFontHeight ); continue; } line->PerformFadeout(); line->SetSize( w, m_iFontHeight * line->GetNumLines() ); line->SetPos( 0, ( currentY+m_iFontHeight) - m_iFontHeight * line->GetNumLines() ); currentY -= ystep * line->GetNumLines(); } if ( currentY != startY ) { m_nVisibleHeight = startY - currentY + 2; } else { m_nVisibleHeight = 0; } vgui::surface()->MovePopupToBack( GetVPanel() ); #endif }