diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/hud_lcd.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/hud_lcd.cpp')
| -rw-r--r-- | mp/src/game/client/hud_lcd.cpp | 3186 |
1 files changed, 1593 insertions, 1593 deletions
diff --git a/mp/src/game/client/hud_lcd.cpp b/mp/src/game/client/hud_lcd.cpp index c7002fad..0f0609d6 100644 --- a/mp/src/game/client/hud_lcd.cpp +++ b/mp/src/game/client/hud_lcd.cpp @@ -1,1593 +1,1593 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: LCD support
-//
-//=====================================================================================//
-
-#if defined( WIN32 ) && !defined( _X360 )
-#include <windows.h>
-#endif
-
-#include "cbase.h"
-
-#ifdef POSIX
-#define HICON int
-const int DT_LEFT = 1;
-const int DT_CENTER = 2;
-const int DT_RIGHT = 3;
-#endif
-
-#include "hud_lcd.h"
-
-#include "vgui_controls/Controls.h"
-#include "vgui_controls/SectionedListPanel.h"
-#include "vgui/ISurface.h"
-#include "vgui/IScheme.h"
-#include "vgui/IVGui.h"
-#include "vgui/ILocalize.h"
-#include "vgui/IPanel.h"
-
-#include "c_team.h"
-#include "c_playerresource.h"
-#include "filesystem.h"
-#include "g15/ig15.h"
-
-#include "tier0/icommandline.h"
-
-#if defined( _X360 )
-#include "xbox/xbox_win32stubs.h"
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define G15_RESOURCE_FILE "resource/g15.res"
-#define G15_MODULE_NAME "bin/g15.dll"
-
-#define SMALL_ITEM_HEIGHT 10
-#define G15_DEFAULT_MAX_CHAT_HISTORY 4
-
-CLCD gLCD;
-IHudLCD *hudlcd = &gLCD;
-
-CON_COMMAND( g15_reload, "Reloads the Logitech G-15 Keyboard configs." )
-{
- if ( !CommandLine()->FindParm( "-g15" ) )
- {
- Msg( "Must run with -g15 to enable support for the LCD Keyboard\n" );
- return;
- }
-
- gLCD.Reload();
-}
-
-CON_COMMAND( g15_dumpplayer, "Spew player data." )
-{
- if ( !CommandLine()->FindParm( "-g15" ) )
- {
- Msg( "Must run with -g15 to enable support for the LCD Keyboard\n" );
- return;
- }
-
- gLCD.DumpPlayer();
-}
-
-static ConVar g15_update_msec( "g15_update_msec", "250", FCVAR_ARCHIVE, "Logitech G-15 Keyboard update interval." );
-
-void CLCDItem::Wipe( IG15 *lcd )
-{
- for ( int i = 0; i < m_Children.Count(); ++i )
- {
- if ( m_Children[ i ]->m_Handle )
- {
- lcd->RemoveAndDestroyObject( m_Children[ i ]->m_Handle );
- }
-
- m_Children[ i ]->Wipe( lcd );
-
- delete m_Children[ i ];
- }
-
- m_Children.Purge();
-
-}
-void CLCDItemAggregate::Create( IG15 *lcd )
-{
- // Nothing
-}
-
-void CLCDItemAggregate::Wipe( IG15 *lcd )
-{
- BaseClass::Wipe( lcd );
-
- for ( int i = 0; i < m_Definition.Count(); ++i )
- {
- m_Definition[ i ]->Wipe( lcd );
-
- delete m_Definition[ i ];
- }
-
- m_Definition.Purge();
-}
-
-void CLCDItemAggregate::WipeChildrenOnly( IG15 *lcd )
-{
- BaseClass::Wipe( lcd );
-}
-
-void CLCDItemIcon::Create( IG15 *lcd )
-{
-#ifdef WIN32
- m_Handle = lcd->AddIcon( (HICON)m_icon, w, h );
-#else
- m_Handle = lcd->AddIcon( (void *)m_icon, w, h );
-#endif
- lcd->SetOrigin( m_Handle, x, y );
- lcd->SetVisible( m_Handle, false );
-}
-
-void CLCDItemText::Create( IG15 *lcd )
-{
- m_Handle = lcd->AddText( G15_STATIC_TEXT, (G15TextSize)m_iSize, m_iAlign, w );
- lcd->SetOrigin( m_Handle, x, y );
- lcd->SetText( m_Handle, m_OriginalText );
- lcd->SetVisible( m_Handle, false );
-}
-
-
-///-----------------------------------------------------------------------------
-/// Constructor
-///-----------------------------------------------------------------------------
-CLCD::CLCD( void )
- : m_lcd( NULL ),
- m_nCurrentPage( 0 ),
- m_nSubPage( 0 ),
- m_bHadPlayer( false ),
- m_dwNextUpdateTime( 0u ),
- m_nMaxChatHistory( G15_DEFAULT_MAX_CHAT_HISTORY ),
- m_pG15Module( 0 ),
- m_G15Factory( 0 )
-{
- m_Size[ 0 ] = m_Size[ 1 ] = 0;
-}
-
-///-----------------------------------------------------------------------------
-/// Destructor
-///-----------------------------------------------------------------------------
-CLCD::~CLCD( void )
-{
-}
-
-void CLCD::Reload()
-{
- Shutdown();
-
- Msg( "Reloading G15 config\n" );
-
- Init();
-}
-
-///------------------------------------------------------------------------------
-/// Initializes the LCD device, and sets up the text handles
-///------------------------------------------------------------------------------
-void CLCD::Init( void )
-{
- if ( !CommandLine()->FindParm( "-g15" ) )
- return;
-
- if ( m_lcd )
- return;
-
- m_pG15Module = Sys_LoadModule( G15_MODULE_NAME );
- if ( !m_pG15Module )
- {
- return;
- }
-
- m_G15Factory = Sys_GetFactory( m_pG15Module );
- if ( !m_G15Factory )
- {
- Shutdown();
- return;
- }
-
- m_lcd = reinterpret_cast< IG15 * >( m_G15Factory( G15_INTERFACE_VERSION, NULL ) );
- if ( !m_lcd )
- {
- Shutdown();
- return;
- }
-
- m_lcd->GetLCDSize( m_Size[ 0 ], m_Size[ 1 ] );
-
- m_nCurrentPage = 0;
- m_nSubPage = 0;
-
- m_TextSizes.Insert( "small", G15_SMALL );
- m_TextSizes.Insert( "medium", G15_MEDIUM );
- m_TextSizes.Insert( "big", G15_BIG );
-
- m_TextAlignments.Insert( "left", DT_LEFT );
- m_TextAlignments.Insert( "center", DT_CENTER );
- m_TextAlignments.Insert( "right", DT_RIGHT );
-
- KeyValues *kv = new KeyValues( "G15" );
- if ( kv->LoadFromFile( filesystem, G15_RESOURCE_FILE, "MOD" ) )
- {
- char const *title = kv->GetString( "game", "Source Engine" );
- m_nMaxChatHistory = clamp( 1, kv->GetInt( "chatlines", m_nMaxChatHistory ), 64 );
- Assert( title );
- m_Title = title;
- m_lcd->Init( m_Title.String() );
-
- for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
- {
- char const *keyName = sub->GetName();
- if ( !Q_stricmp( keyName, "game" ) )
- {
- // Handled above!!!
- }
- else if ( !Q_stricmp( keyName, "icons" ) )
- {
- ParseIconMappings( sub );
- }
- else if ( !Q_stricmp( keyName, "replace" ) )
- {
- ParseReplacements( sub );
- }
- else if ( !Q_stricmp( keyName, "page" ) )
- {
- ParsePage( sub );
- }
- }
- }
- kv->deleteThis();
-
- UpdateChat();
-
- Msg( "Logitech LCD Keyboard initialized\n" );
-}
-
-///--------------------------------------------------------------------------
-/// Destroys the local EZ LCD Object
-///--------------------------------------------------------------------------
-void CLCD::Shutdown( void )
-{
- for ( int i = 0; i < m_Pages.Count(); ++i )
- {
- CLCDPage *page = m_Pages[ i ];
- page->Wipe( m_lcd );
- delete page;
- }
-
- m_Pages.Purge();
-
- if ( m_lcd )
- {
- m_lcd->Shutdown();
- m_lcd = NULL;
- }
-
- m_TextSizes.Purge();
- m_TextAlignments.Purge();
- m_GlobalStats.Purge();
-
- m_G15Factory = 0;
-
- if ( m_pG15Module )
- {
- Sys_UnloadModule( m_pG15Module );
- m_pG15Module = 0;
- }
-}
-
-int CLCD::FindTitlePage()
-{
- for ( int i = 0; i < m_Pages.Count(); ++i )
- {
- if ( m_Pages[ i ]->m_bTitlePage )
- return i;
- }
-
- return -1;
-}
-
-bool CLCD::IsPageValid( int currentPage, C_BasePlayer *player )
-{
- if ( m_Pages[ currentPage ]->m_bTitlePage && player )
- return false;
-
- if ( m_Pages[ currentPage ]->m_bRequiresPlayer && !player )
- return false;
-
- return true;
-}
-
-///---------------------------------------------------------------------
-/// Update routine
-///---------------------------------------------------------------------
-void CLCD::Update( void )
-{
- if ( !m_lcd )
- return ;
-
- C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
- bool hasplayer = player ? true : false;
-
- bool changed = hasplayer != m_bHadPlayer;
- m_bHadPlayer = hasplayer;
-
- int pageCount = m_Pages.Count();
-
- int prevPage = m_nCurrentPage;
-
- if ( pageCount > 0 )
- {
- bool force = false;
- if ( changed && hasplayer )
- {
- force = true;
- m_nCurrentPage = 0;
- m_nSubPage = 0;
- }
-
- if ( !IsPageValid( m_nCurrentPage, player ) )
- {
- force = true;
- }
-
- if ( m_lcd->ButtonTriggered( G15_BUTTON_1 ) || force )
- {
- m_nSubPage = 0;
-
- for ( int i = 0; i < pageCount; ++i )
- {
- m_nCurrentPage = ( m_nCurrentPage + 1 ) % pageCount;
- if ( !IsPageValid( m_nCurrentPage, player ) )
- continue;
-
-
-
- break;
- }
- }
-
- if ( m_lcd->ButtonTriggered( G15_BUTTON_2 ) )
- {
- int pc = m_Pages[ m_nCurrentPage ]->m_nSubPageCount;
-
- m_nSubPage = ( m_nSubPage + 1 ) % pc;
- }
- }
- else
- {
- m_nCurrentPage = -1;
- m_nSubPage = 0;
- }
-
- bool pageChanged = prevPage != m_nCurrentPage;
-
- unsigned int dwCurTime = (unsigned int)( 1000.0 * gpGlobals->realtime );
-
- if ( m_lcd->IsConnected() )
- {
- if ( dwCurTime >= m_dwNextUpdateTime || pageChanged )
- {
- m_dwNextUpdateTime = dwCurTime + g15_update_msec.GetInt();
- DisplayCurrentPage( dwCurTime );
- }
- }
-
- m_lcd->UpdateLCD( dwCurTime );
-}
-
-///--------------------------------------------------------------------------
-///
-///--------------------------------------------------------------------------
-bool CLCD::IsConnected( void ) const
-{
- return m_lcd ? m_lcd->IsConnected() : false;
-}
-
-void CLCD::ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCDItem * >& list, bool bShowItems )
-{
- int itemCount = list.Count();
- for ( int j = 0; j < itemCount; ++j )
- {
- CLCDItem *item = list[ j ];
- if ( !item->m_bActive )
- continue;
-
- if ( bShowItems )
- {
- switch ( item->m_Type )
- {
- default:
- break;
- case LCDITEM_TEXT:
- {
- CLCDItemText *txt = static_cast< CLCDItemText * >( item );
- if ( txt )
- {
- // Need to build updated text
- CUtlString updated;
- CUtlString str = txt->m_OriginalText;
- BuildUpdatedText( str.String(), updated );
- DoGlobalReplacements( updated );
- ReduceParentheses( updated );
-
- m_lcd->SetText( item->m_Handle, updated.String() );
- }
- }
- break;
- case LCDITEM_ICON:
- {
- CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( item );
- if ( icon )
- {
- // Need to build updated text
- CUtlString updated;
- CUtlString str = icon->m_IconName;
- BuildUpdatedText( str.String(), updated );
- DoGlobalReplacements( updated );
- ReduceParentheses( updated );
-
- int idx = m_Icons.Find( updated.String() );
- if ( idx != m_Icons.InvalidIndex() )
- {
- icon->m_icon = (void *)m_Icons[ idx ].m_handle;
- }
-
- // Recreate
- if ( icon->m_Handle )
- {
- m_lcd->RemoveAndDestroyObject( icon->m_Handle );
- icon->m_Handle = 0;
- }
- icon->Create( m_lcd );
- }
- }
- break;
- case LCDITEM_AGGREGATE:
- {
- CLCDItemAggregate *ag = static_cast< CLCDItemAggregate * >( item );
- if ( ag->m_dwNextUpdateTime > dwCurTime )
- break;
-
- // FIXME: encode update interval in text file
- ag->m_dwNextUpdateTime = dwCurTime + 1000;
-
- // Blow away current data
- ag->WipeChildrenOnly( m_lcd );
-
- CUtlVector< int > validIndices;
- char prefix[ 256 ];
- char altprefix[ 256 ];
- prefix[ 0 ] = 0;
- altprefix[ 0 ] = 0;
-
- int curx = ag->x;
- int cury = ag->y;
-
- switch ( ag->m_AggType )
- {
- default:
- Assert( 0 );
- break;
- case AGGTYPE_PERPLAYER:
- // Add all players into list
- {
- for ( int pl = 1; pl <= gpGlobals->maxClients; ++pl )
- {
- if ( g_PR && g_PR->IsConnected( pl ) )
- {
- validIndices.AddToTail( pl );
- }
- }
-
- Q_strncpy( prefix, "(playerindex)", sizeof( prefix ) );
- Q_strncpy( altprefix, "(playerindexplusone)", sizeof( altprefix ) );
- }
- break;
- case AGGTYPE_PERTEAM:
- {
- C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
-
- if ( local )
- {
- for ( int pl = 1; pl <= gpGlobals->maxClients; ++pl )
- {
- if ( g_PR && g_PR->IsConnected( pl ) && local->GetTeamNumber() == g_PR->GetTeam( pl ) )
- {
- validIndices.AddToTail( pl );
- }
- }
- }
-
- Q_strncpy( prefix, "(playerindex)", sizeof( prefix ) );
- Q_strncpy( altprefix, "(playerindexplusone)", sizeof( altprefix ) );
- }
- break;
- }
-
- int subPage = 0;
- int spItems = 0;
-
- int ecount = validIndices.Count();
- for ( int e = 0; e < ecount; ++e )
- {
- // Now fixup any strings
- int index = validIndices[ e ];
-
- char s1[ 512 ], s2[ 512 ];
- Q_snprintf( s1, sizeof( s1 ), "%d", index );
- Q_snprintf( s2, sizeof( s2 ), "%d", index + 1 );
-
- // Now replace "playerindex" with the index as needed
- for( int r = 0; r < ag->m_Definition.Count(); ++r )
- {
- CLCDItem *newItem = NULL;
-
- CLCDItem *item = ag->m_Definition[ r ];
- switch ( item->m_Type )
- {
- default:
- break;
-
- case LCDITEM_TEXT:
- {
- CLCDItemText *text = static_cast< CLCDItemText * >( item );
- CUtlString s;
- s = text->m_OriginalText;
- Replace( s, prefix, s1 );
- Replace( s, altprefix, s2 );
- char itemNumber[ 32 ];
- Q_snprintf( itemNumber, sizeof( itemNumber ), "%d", e +1 );
-
- Replace( s, "(itemnumber)", itemNumber );
-
- DoGlobalReplacements( s );
- // ReduceParentheses( s );
-
- // text->m_OriginalText = s;
-
- CLCDItemText *copy = static_cast< CLCDItemText * >( page->Alloc( item->m_Type ) );
- *copy = *text;
- copy->m_bActive = true;
- copy->m_OriginalText = s;
- copy->Create( m_lcd );
-
- m_lcd->SetOrigin( copy->m_Handle, curx + copy->x, cury + copy->y );
-
- newItem = copy;
- }
- break;
- case LCDITEM_ICON:
- {
- CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( item );
- CLCDItemIcon *copy = static_cast< CLCDItemIcon * >( page->Alloc( item->m_Type ) );
- *copy = *icon;
- copy->m_bActive = true;
- copy->Create( m_lcd );
-
- m_lcd->SetOrigin( copy->m_Handle, curx + copy->x, cury + copy->y );
-
- newItem = copy;
- }
- break;
- }
-
- if ( newItem )
- {
- ++spItems;
- newItem->m_nSubPage = subPage;
- ag->m_Children.AddToTail( newItem );
- }
- }
-
- cury += ag->m_yincrement;
-
- if ( cury + SMALL_ITEM_HEIGHT > m_Size[ 1 ] )
- {
- spItems = 0;
- ++subPage;
- cury = ag->y;
- }
- }
-
- if ( spItems > 0 )
- {
- page->m_nSubPageCount = subPage + 1;
- }
- else
- {
- // We thought we needed a new page, but didn't actually use it
- page->m_nSubPageCount = subPage;
- }
- }
- }
- }
-
- m_lcd->SetVisible( item->m_Handle, bShowItems && ( ( item->m_nSubPage == -1 ) || item->m_nSubPage == m_nSubPage ) );
-
- ShowItems_R( page, dwCurTime, item->m_Children, bShowItems );
- }
-}
-
-void CLCD::DisplayCurrentPage( unsigned int dwCurTime )
-{
- int pageCount = m_Pages.Count();
- for ( int i = 0; i < pageCount; ++i )
- {
- bool bShowItems = ( i == m_nCurrentPage ) ? true : false;
-
- CLCDPage* page = m_Pages[ i ];
- ShowItems_R( page, dwCurTime, page->m_Children, bShowItems );
- }
-}
-
-CLCDItemIcon *CLCD::ParseItemIcon( CLCDPage *page, bool bCreateHandles, KeyValues *sub )
-{
- CLCDItemIcon *item = static_cast< CLCDItemIcon * >( page->Alloc( LCDITEM_ICON ) );
-
- item->m_IconName = sub->GetString( "name", "" );
-
- item->m_nSubPage = sub->GetInt( "header", 0 ) ? -1 : page->m_nSubPageCount - 1;
- item->w = sub->GetInt( "w", 24 );
- item->h = sub->GetInt( "h", 24 );
- item->x = sub->GetInt( "x", 0 );
- item->y = sub->GetInt( "y", 0 );
-
- int idx = m_Icons.Find( item->m_IconName.String() );
- item->m_icon = 0;
- if ( idx != m_Icons.InvalidIndex() )
- {
- item->m_icon = (void *)m_Icons[ idx ].m_handle;
- }
-
- if ( bCreateHandles )
- {
- item->Create( m_lcd );
- }
-
- return item;
-}
-
-CLCDItemText *CLCD::ParseItemText( CLCDPage *page, bool bCreateHandles, KeyValues *sub )
-{
- CLCDItemText *item = static_cast< CLCDItemText * >( page->Alloc( LCDITEM_TEXT ) );
-
- const char *initialText = sub->GetString( "text", "" );
- item->m_bHasWildcard = Q_strstr( initialText, "%" ) ? true : false;
-
- item->m_nSubPage = sub->GetInt( "header", 0 ) ? -1 : page->m_nSubPageCount - 1;
- item->w = sub->GetInt( "w", 150 );
- item->x = sub->GetInt( "x", 0 );
- item->y = sub->GetInt( "y", 0 );
-
- const char *sizeStr = sub->GetString( "size", "small" );
- item->m_iSize = G15_SMALL;
- int iFound = m_TextSizes.Find( sizeStr );
- if ( iFound != m_TextSizes.InvalidIndex() )
- {
- item->m_iSize = m_TextSizes[ iFound ];
- }
-
- const char *alignStr = sub->GetString( "align", "left" );
- item->m_iAlign = DT_LEFT;
- iFound = m_TextAlignments.Find( alignStr );
- if ( iFound != m_TextAlignments.InvalidIndex() )
- {
- item->m_iAlign = m_TextAlignments[ iFound ];
- }
-
- item->m_OriginalText = initialText;
- if ( bCreateHandles )
- {
- item->Create( m_lcd );
- }
-
- return item;
-}
-
-void CLCD::ParseItems_R( CLCDPage *page, bool bCreateHandles, KeyValues *kv, CUtlVector< CLCDItem * >& list )
-{
- for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
- {
- char const *keyName = sub->GetName();
- if ( !Q_stricmp( keyName, "iterate_players" ) ||
- !Q_stricmp( keyName, "iterate_team" ) )
- {
- int aggType = AGGTYPE_UNKNOWN;
- if ( !Q_stricmp( keyName, "iterate_players" ) )
- {
- aggType = AGGTYPE_PERPLAYER;
- }
- else if ( !Q_stricmp( keyName, "iterate_team" ) )
- {
- aggType = AGGTYPE_PERTEAM;
- }
-
- // Now we parse the items out as we generally would
- CLCDItemAggregate *item = static_cast< CLCDItemAggregate * >( page->Alloc( LCDITEM_AGGREGATE ) );
- item->m_AggType = aggType;
-
- item->x = sub->GetInt( "x", 0 );
- item->y = sub->GetInt( "y", 0 );
- item->m_yincrement = sub->GetInt( "y_increment", 10 );
-
- // Parse the definition
- ParseItems_R( page, false, sub, item->m_Definition );
-
- // Add the definition items as "inactive" items to the scene (so they get destroyed)
- for ( int i = 0; i < item->m_Definition.Count(); ++i )
- {
- CLCDItem *pItem = item->m_Definition[ i ];
- pItem->m_bActive = false;
- }
-
- list.AddToTail( item );
- }
- else if ( !Q_stricmp( keyName, "static_icon" ) )
- {
- CLCDItemIcon *item = ParseItemIcon( page, true, sub );
- Assert( item );
- list.AddToTail(item );
- }
- else if ( !Q_stricmp( keyName, "static_text" ) )
- {
- CLCDItemText *item = ParseItemText( page, true, sub );
- Assert( item );
- list.AddToTail( item );
- }
- else if ( !Q_stricmp( keyName, "newsubpage" ) )
- {
- // Add to new subpage
- ++page->m_nSubPageCount;
- }
- else
- {
- // Skip unknown stuff
- continue;
- }
- }
-}
-
-void CLCD::ParsePage( KeyValues *kv )
-{
- CLCDPage *newPage = new CLCDPage();
- m_Pages.AddToTail( newPage );
-
- newPage->m_bTitlePage = kv->GetInt( "titlepage", 0 ) ? true : false;
- newPage->m_bRequiresPlayer = kv->GetInt( "requiresplayer", 0 ) ? true : false;
-
- ParseItems_R( newPage, true, kv, newPage->m_Children );
-}
-
-void CLCD::ParseIconMappings( KeyValues *kv )
-{
- for ( KeyValues *icon = kv->GetFirstSubKey(); icon; icon = icon->GetNextKey() )
- {
- IconInfo_t info;
- HICON hIcon = 0;
- char const *name = icon->GetName();
- char fullpath[ 512 ];
- filesystem->RelativePathToFullPath( icon->GetString(), "GAME", fullpath, sizeof( fullpath ) );
-#ifdef WIN32
- hIcon = (HICON)::LoadImageA( NULL, fullpath, IMAGE_ICON, 32, 32, LR_LOADFROMFILE );
-#else
- hIcon = 0;
-#endif
- info.m_handle = (void *)hIcon;
- m_Icons.Insert( name, info );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Simply dumps all data fields in object
-//-----------------------------------------------------------------------------
-class CDescribeData
-{
-public:
- CDescribeData( void const *src );
-
- void DescribeShort( const short *invalue, int count );
- void DescribeInt( const int *invalue, int count );
- void DescribeBool( const bool *invalue, int count );
- void DescribeFloat( const float *invalue, int count );
- void DescribeSimpleString( const char *indata, int length );
- void DescribeString( const string_t *instring, int count );
- void DescribeVector( const Vector *inValue, int count );
- void DescribeColor( const Color *invalue, int count );
- void DumpDescription( datamap_t *pMap );
-
- void GetValueForField( char const *fieldName, char *buf, size_t bufsize );
-
-private:
- void DescribeFields_R( int chain_count, datamap_t *pMap, typedescription_t *pFields, int fieldCount );
- bool BuildFieldPath( CUtlString& path );
-
- void const *m_pSrc;
- int m_nSrcOffsetIndex;
-
- void Describe( const char *fmt, ... );
-
- typedescription_t *m_pCurrentField;
- char const *m_pCurrentClassName;
- datamap_t *m_pCurrentMap;
-
- CUtlVector< CUtlString > m_FieldPath;
-};
-
-CDescribeData::CDescribeData( void const *src )
-{
- m_pSrc = src;
- m_nSrcOffsetIndex = TD_OFFSET_NORMAL;
-
- m_pCurrentField = NULL;
- m_pCurrentMap = NULL;
- m_pCurrentClassName = NULL;
-}
-
-typedescription_t *FindFieldByName( datamap_t *pMap, char const *fn )
-{
- while ( pMap )
- {
- for ( int i = 0; i < pMap->dataNumFields; i++ )
- {
- typedescription_t *current = &pMap->dataDesc[ i ];
- if ( !current->fieldName )
- continue;
-
- if ( !Q_stricmp( current->fieldName, fn ) )
- return current;
- }
-
- pMap = pMap->baseMap;
- }
-
- return NULL;
-}
-
-typedescription_t *FindField( datamap_t *pMap, char const *relativePath )
-{
- if ( !Q_strstr( relativePath, "." ) )
- {
- // Simple case, just look up field name
- return FindFieldByName( pMap, relativePath );
- }
-
- // Complex case
-
- Assert( 0 );
- return NULL;
-}
-
-bool CDescribeData::BuildFieldPath( CUtlString& path )
-{
- int c = m_FieldPath.Count();
- if ( c == 0 )
- return false;
-
- for ( int i = 0; i < c; ++i )
- {
- CUtlString& s = m_FieldPath[ i ];
- if ( i != 0 )
- {
- path += ".";
- }
- path += s;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *fmt -
-// ... -
-//-----------------------------------------------------------------------------
-void CDescribeData::Describe( const char *fmt, ... )
-{
- Assert( m_pCurrentMap );
- Assert( m_pCurrentClassName );
-
- const char *fieldname = "empty";
-
- if ( m_pCurrentField )
- {
- fieldname = m_pCurrentField->fieldName ? m_pCurrentField->fieldName : "NULL";
- }
-
- va_list argptr;
- char data[ 4096 ];
- int len;
- va_start(argptr, fmt);
- len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
- va_end(argptr);
-
- CUtlString fp;
- if ( BuildFieldPath( fp ) )
- {
- Msg( "%s.%s%s",
- fp.String(),
- fieldname,
- data );
- }
- else
- {
- Msg( "%s%s",
- fieldname,
- data );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : size -
-// *outdata -
-// *indata -
-//-----------------------------------------------------------------------------
-void CDescribeData::DescribeSimpleString( char const *invalue, int count )
-{
- Describe( "%s\n", invalue ? invalue : "" );
-}
-
-
-void CDescribeData::DescribeShort( const short *invalue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " short (%i)\n", (int)(invalue[i]) );
- }
- else
- {
- Describe( "[%i] short (%i)\n", i, (int)(invalue[i]) );
- }
- }
-}
-
-
-void CDescribeData::DescribeInt( const int *invalue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " integer (%i)\n", invalue[i] );
- }
- else
- {
- Describe( "[%i] integer (%i)\n", i, invalue[i] );
- }
- }
-}
-
-void CDescribeData::DescribeBool( const bool *invalue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " bool (%s)\n", (invalue[i]) ? "true" : "false" );
- }
- else
- {
- Describe( "[%i] bool (%s)\n", i, (invalue[i]) ? "true" : "false" );
- }
- }
-}
-
-void CDescribeData::DescribeFloat( const float *invalue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " float (%f)\n", invalue[ i ] );
- }
- else
- {
- Describe( "[%i] float (%f)\n", i, invalue[ i ] );
- }
- }
-}
-
-void CDescribeData::DescribeString( const string_t *instring, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " string (%s)\n", instring[ i ] ? instring[ i ] : "" );
- }
- else
- {
- Describe( "[%i] string (%s)\n", i, instring[ i ] ? instring[ i ] : "" );
- }
- }
-}
-
-void CDescribeData::DescribeColor( const Color *invalue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " color (%i %i %i %i)\n", invalue[ i ].r(), invalue[ i ].g(), invalue[ i ].b(), invalue[ i ].a() );
- }
- else
- {
- Describe( "[%i] color (%i %i %i %i)\n", i, invalue[ i ].r(), invalue[ i ].g(), invalue[ i ].b(), invalue[ i ].a() );
- }
- }
-}
-
-void CDescribeData::DescribeVector( const Vector *inValue, int count )
-{
- for ( int i = 0; i < count; ++i )
- {
- if ( count == 1 )
- {
- Describe( " vector (%f %f %f)\n",
- inValue[i].x, inValue[i].y, inValue[i].z );
- }
- else
- {
- Describe( "[%i] vector (%f %f %f)\n",
- i,
- inValue[i].x, inValue[i].y, inValue[i].z );
- }
- }
-}
-
-void CDescribeData::DescribeFields_R( int chain_count, datamap_t *pRootMap, typedescription_t *pFields, int fieldCount )
-{
- int i;
- int flags;
- int fieldOffsetSrc;
- int fieldSize;
-
- m_pCurrentMap = pRootMap;
- if ( !m_pCurrentClassName )
- {
- m_pCurrentClassName = pRootMap->dataClassName;
- }
-
- for ( i = 0; i < fieldCount; i++ )
- {
- m_pCurrentField = &pFields[ i ];
- flags = m_pCurrentField->flags;
-
- // Skip this field
- if ( flags & FTYPEDESC_VIEW_NEVER )
- continue;
-
- // Mark any subchains first
- if ( m_pCurrentField->override_field != NULL )
- {
- m_pCurrentField->override_field->override_count = chain_count;
- }
-
- // Skip this field?
- if ( m_pCurrentField->override_count == chain_count )
- {
- continue;
- }
-
- void const *pInputData;
-
- fieldOffsetSrc = m_pCurrentField->fieldOffset[ m_nSrcOffsetIndex ];
- fieldSize = m_pCurrentField->fieldSize;
-
- pInputData = (void const *)((char *)m_pSrc + fieldOffsetSrc );
-
- switch( m_pCurrentField->fieldType )
- {
- default:
- break;
- case FIELD_EMBEDDED:
- {
- typedescription_t *save = m_pCurrentField;
- void const *saveSrc = m_pSrc;
- const char *saveName = m_pCurrentClassName;
-
- m_pCurrentClassName = m_pCurrentField->td->dataClassName;
-
- CUtlString str;
- str = m_pCurrentField->fieldName;
-
- m_FieldPath.AddToTail( str );
-
- m_pSrc = pInputData;
- if ( ( flags & FTYPEDESC_PTR ) && (m_nSrcOffsetIndex == PC_DATA_NORMAL) )
- {
- m_pSrc = *((void**)m_pSrc);
- }
-
- DescribeFields_R( chain_count, pRootMap, m_pCurrentField->td->dataDesc, m_pCurrentField->td->dataNumFields );
-
- m_FieldPath.Remove( m_FieldPath.Count() - 1 );
-
- m_pCurrentClassName = saveName;
- m_pCurrentField = save;
- m_pSrc = saveSrc;
- }
- break;
- case FIELD_FLOAT:
- DescribeFloat( (float const *)pInputData, fieldSize );
- break;
- case FIELD_STRING:
- DescribeString( (const string_t*)pInputData, fieldSize );
- break;
- case FIELD_VECTOR:
- DescribeVector( (const Vector *)pInputData, fieldSize );
- break;
- case FIELD_COLOR32:
- DescribeColor( (const Color *)pInputData, fieldSize );
- break;
-
- case FIELD_BOOLEAN:
- DescribeBool( (bool const *)pInputData, fieldSize );
- break;
- case FIELD_INTEGER:
- DescribeInt( (int const *)pInputData, fieldSize );
- break;
-
- case FIELD_SHORT:
- DescribeShort( (short const *)pInputData, fieldSize );
- break;
-
- case FIELD_CHARACTER:
- DescribeSimpleString( (const char *)pInputData, fieldSize );
- break;
- }
- }
-
- m_pCurrentClassName = NULL;
-}
-
-static int g_nChainCount = 1;
-extern void ValidateChains_R( datamap_t *dmap );
-
-void CDescribeData::DumpDescription( datamap_t *pMap )
-{
- ++g_nChainCount;
-
- if ( !pMap->chains_validated )
- {
- ValidateChains_R( pMap );
- }
-
- while ( pMap )
- {
- DescribeFields_R( g_nChainCount, pMap, pMap->dataDesc, pMap->dataNumFields );
-
- pMap = pMap->baseMap;
- }
-}
-
-
-void CLCD::DumpPlayer()
-{
- C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
- if ( !player )
- return;
-
- Msg( "(localplayer)\n\n" );
-
- CDescribeData helper( player );
- helper.DumpDescription( player->GetPredDescMap() );
-
- Msg( "(localteam)\n\n" );
-
- C_Team *team = player->GetTeam();
- if ( team )
- {
- CDescribeData helper( team );
- helper.DumpDescription( team->GetPredDescMap() );
- }
-
- Msg( "(playerresource)\n\n" );
-
- if ( g_PR )
- {
- CDescribeData helper( g_PR );
- helper.DumpDescription( g_PR->GetPredDescMap() );
- }
-
- Msg( "(localplayerweapon)\n\n" );
- // Get the player's weapons, too
- C_BaseCombatWeapon *active = player->GetActiveWeapon();
- if ( active )
- {
- CDescribeData helper( active );
- helper.DumpDescription( active->GetPredDescMap() );
- }
-
- Msg( "Other replacements:\n\n" );
-
- // Global replacements
- for( int i = m_GlobalStats.First() ; i != m_GlobalStats.InvalidIndex(); i = m_GlobalStats.Next( i ) )
- {
- CUtlString& r = m_GlobalStats[ i ];
-
- char const *pReplace = r.String();
- char ansi[ 512 ];
- ansi[ 0 ] = 0;
-
- if ( pReplace[ 0 ] == '#' )
- {
- const wchar_t *pWString = g_pVGuiLocalize->Find( pReplace );
- if ( pWString )
- {
- g_pVGuiLocalize->ConvertUnicodeToANSI( pWString, ansi, sizeof( ansi ) );
- pReplace = ansi;
- }
- }
-
- Msg( "'%s' = '%s'\n", m_GlobalStats.GetElementName( i ), pReplace );
- }
-}
-
-bool CLCD::ExtractArrayIndex( char *str, size_t bufsize, int *index )
-{
- Assert( index );
- *index = 0;
-
- char s[ 2048 ];
- Q_strncpy( s, str, sizeof( s ) );
-
- char *pos = Q_strstr( s, "[" );
- if ( !pos )
- return false;
-
- char *pos2 = Q_strstr( s, "]" );
- if ( !pos2 )
- return false;
-
- char num[ 32 ];
- Q_strncpy( num, pos + 1, pos2 - pos );
- *index = Q_atoi( num );
-
- int left = pos - s + 1;
- char o[ 2048 ];
- Q_strncpy( o, s, left );
- Q_strncat( o, pos2 + 1, sizeof( o ), COPY_ALL_CHARACTERS );
-
- Q_strncpy( str, o, bufsize );
- return true;
-}
-
-void CLCD::LookupToken( char const *in, CUtlString& value )
-{
- value = "";
-
- C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
- if ( !player )
- {
- return;
- }
-
- C_BaseEntity *ref = NULL;
-
- char outbuf[ 1024 ];
- char *o = outbuf;
- char const *i = in;
- while ( *i )
- {
- if ( *i == '(' )
- {
- char token[ 512 ];
- char *to = token;
- // swallow everything until matching '%' character
- ++i;
- while ( *i && *i != ')' )
- {
- *to++ = *i++;
- }
-
- if ( *i )
- ++i;
-
- *to = 0;
-
- if ( !Q_stricmp( token, "localplayer" ) )
- {
- ref = player;
- }
- else if ( !Q_stricmp( token, "localteam" ) )
- {
- ref = player->GetTeam();
- }
- else if ( !Q_stricmp( token, "localplayerweapon" ) )
- {
- ref = player->GetActiveWeapon();
- }
- else if ( !Q_stricmp( token, "playerresource" ) )
- {
- ref = g_PR;
- }
- }
- else
- {
- *o++ = *i++;
- }
- }
-
- *o = '\0';
-
- // Fixme, also need to get array reference removed from end and do the . field searching stuff
-
- // Outbuf now has the actual field
- if ( !ref )
- {
- return;
- }
-
- int iIndex = 0;
- ExtractArrayIndex( outbuf, sizeof( outbuf ), &iIndex );
-
- typedescription_t *td = FindField( ref->GetPredDescMap(), outbuf );
- if ( !td )
- {
- return;
- }
-
- // Not allowed to see this one
- if ( td->flags & FTYPEDESC_VIEW_NEVER )
- {
- return;
- }
-
- int fieldOffsetSrc = td->fieldOffset[ TD_OFFSET_NORMAL ];
- // int fieldSize = td->fieldSize;
-
- void const *pInputData = (void const *)((char *)ref + fieldOffsetSrc );
-
- char sz[ 256 ];
- sz[ 0 ] = 0;
- // Found it, now get the value
- switch ( td->fieldType )
- {
- case FIELD_FLOAT:
- Q_snprintf( sz, sizeof( sz ), "%.2f", *((float *)pInputData + iIndex ) );
- break;
- case FIELD_STRING:
- {
- string_t *pString = (string_t *)((string_t *)pInputData + iIndex );
- Q_snprintf( sz, sizeof( sz ), "%s", pString ? STRING( *pString ) : "" );
- }
- break;
- case FIELD_VECTOR:
- {
- Vector v = *((Vector *)pInputData + iIndex );
- Q_snprintf( sz, sizeof( sz ), "%.2f %.2f %.2f", v.x, v.y, v.z );
- }
- break;
- case FIELD_COLOR32:
- {
- Color c = *(( Color * )pInputData + iIndex );
- Q_snprintf( sz, sizeof( sz ), "%d %d %d %d", c.r(), c.g(), c.b(), c.a() );
- }
- break;
-
- case FIELD_BOOLEAN:
- Q_snprintf( sz, sizeof( sz ), "%s", *( ( bool *)pInputData + iIndex ) ? "true" : "false" );
- break;
- case FIELD_INTEGER:
- Q_snprintf( sz, sizeof( sz ), "%i", *( (int *)pInputData + iIndex ));
- break;
-
- case FIELD_SHORT:
- Q_snprintf( sz, sizeof( sz ), "%i", *( (short *)pInputData + iIndex ) );
- break;
-
- case FIELD_CHARACTER:
- Q_snprintf( sz, sizeof( sz ), "%s", ((const char *)pInputData + iIndex ) );
- break;
- }
-
- value = sz;
-}
-
-void CLCD::BuildUpdatedText( char const *in, CUtlString& out )
-{
- char outbuf[ 1024 ];
- char *o = outbuf;
- char const *i = in;
- while ( *i )
- {
- if ( *i == '%' )
- {
- char token[ 512 ];
- char *to = token;
- // swallow everything until matching '%' character
- ++i;
- while ( *i && *i != '%' )
- {
- *to++ = *i++;
- }
-
- if ( *i )
- ++i;
-
- *to = 0;
-
- // Now we have the token, do the lookup
- CUtlString value;
- LookupToken( token, value );
-
- to = (char *)value.String();
- while ( *to )
- {
- *o++ = *to++;
- }
- }
- else
- {
- *o++ = *i++;
- }
- }
-
- *o = '\0';
-
- out = outbuf;
-}
-
-
-bool CLCD::Replace( CUtlString& str, char const *search, char const *replace )
-{
- // If search string is part of replacement, this is a bad thing!!!
- Assert( !*replace || !Q_strstr( replace, search ) );
-
- bool changed = false;
- if ( !Q_strstr( str.String(), search ) )
- return false;
-
- char s[ 2048 ];
- Q_strncpy( s, str.String(), sizeof( s ) );
-
- int searchlen = Q_strlen( search );
- while ( true )
- {
- char *pos = Q_strstr( s, search );
- if ( !pos )
- break;
-
- char temp[ 4096 ];
- // Found an instance
- int left = pos - s + 1;
- Assert( left < sizeof( temp ) );
- Q_strncpy( temp, s, left );
- Q_strncat( temp, replace, sizeof( temp ), COPY_ALL_CHARACTERS );
- int rightofs = left + searchlen - 1;
- Q_strncat( temp, &s[ rightofs ], sizeof( temp ), COPY_ALL_CHARACTERS );
-
- // Replace entire string
- Q_strncpy( s, temp, sizeof( s ) );
- changed = true;
- }
-
- str = s;
-
- return changed;
-}
-
-void CLCD::SetGlobalStat( char const *name, char const *value )
-{
- if ( !m_lcd )
- return;
-
- int idx = m_GlobalStats.Find( name );
- if ( idx == m_GlobalStats.InvalidIndex() )
- {
- idx = m_GlobalStats.Insert( name );
- }
-
- m_GlobalStats[ idx ] = value;
-}
-
-void CLCD::AddChatLine( char const *txt )
-{
- if ( !m_lcd )
- return;
-
- while ( m_ChatHistory.Count() >= m_nMaxChatHistory )
- {
- m_ChatHistory.Remove( 0 );
- }
-
- m_ChatHistory.AddToTail( CUtlString( txt ) );
-
- UpdateChat();
-}
-
-void CLCD::UpdateChat()
-{
- for ( int i = 0; i < m_nMaxChatHistory; ++i )
- {
- char name[ 32 ];
- Q_snprintf( name, sizeof( name ), "chat_%d", i + 1 );
-
- SetGlobalStat( name, i < m_ChatHistory.Count() ? m_ChatHistory[ i ].String() : " " );
- }
-}
-
-void CLCD::DoGlobalReplacements( CUtlString& str )
-{
- // Put some limit to avoid infinite recursion
- int maxChanges = 16;
-
- bool changed = false;
- do
- {
- changed = false;
- for ( int i = m_GlobalStats.First(); i != m_GlobalStats.InvalidIndex(); i = m_GlobalStats.Next( i ) )
- {
- CUtlString &r = m_GlobalStats[ i ];
-
- char const *pReplace = r.String();
- char ansi[ 512 ];
- ansi[ 0 ] = 0;
-
- if ( pReplace[ 0 ] == '#' )
- {
- const wchar_t *pWString = g_pVGuiLocalize->Find( pReplace );
- if ( pWString )
- {
- g_pVGuiLocalize->ConvertUnicodeToANSI( pWString, ansi, sizeof( ansi ) );
- pReplace = ansi;
- }
- }
-
- if ( Replace( str, m_GlobalStats.GetElementName( i ), pReplace ) )
- {
- changed = true;
- }
- }
- } while ( changed && --maxChanges >= 0 );
-}
-
-void CLCD::ReduceParentheses( CUtlString& str )
-{
- char s[ 2048 ];
- Q_strncpy( s, str.String(), sizeof( s ) );
-
- while ( true )
- {
- char *pos = Q_strstr( s, "(" );
- if ( !pos )
- break;
-
- char *end = Q_strstr( pos, ")" );
- if ( !end )
- break;
-
- char temp[ 4096 ];
- // Found an instance
- int left = pos - s + 1;
- Assert( left < sizeof( temp ) );
- Q_strncpy( temp, s, left );
- int rightofs = end - s + 1;
- Q_strncat( temp, &s[ rightofs ], sizeof( temp ), COPY_ALL_CHARACTERS );
-
- // Replace entire string
- Q_strncpy( s, temp, sizeof( s ) );
- }
-
- str = s;
-}
-
-void CLCD::ParseReplacements( KeyValues *kv )
-{
- for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
- {
- char const *key = sub->GetName();
- char const *value = sub->GetString();
-
- SetGlobalStat( key, value );
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: LCD support +// +//=====================================================================================// + +#if defined( WIN32 ) && !defined( _X360 ) +#include <windows.h> +#endif + +#include "cbase.h" + +#ifdef POSIX +#define HICON int +const int DT_LEFT = 1; +const int DT_CENTER = 2; +const int DT_RIGHT = 3; +#endif + +#include "hud_lcd.h" + +#include "vgui_controls/Controls.h" +#include "vgui_controls/SectionedListPanel.h" +#include "vgui/ISurface.h" +#include "vgui/IScheme.h" +#include "vgui/IVGui.h" +#include "vgui/ILocalize.h" +#include "vgui/IPanel.h" + +#include "c_team.h" +#include "c_playerresource.h" +#include "filesystem.h" +#include "g15/ig15.h" + +#include "tier0/icommandline.h" + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define G15_RESOURCE_FILE "resource/g15.res" +#define G15_MODULE_NAME "bin/g15.dll" + +#define SMALL_ITEM_HEIGHT 10 +#define G15_DEFAULT_MAX_CHAT_HISTORY 4 + +CLCD gLCD; +IHudLCD *hudlcd = &gLCD; + +CON_COMMAND( g15_reload, "Reloads the Logitech G-15 Keyboard configs." ) +{ + if ( !CommandLine()->FindParm( "-g15" ) ) + { + Msg( "Must run with -g15 to enable support for the LCD Keyboard\n" ); + return; + } + + gLCD.Reload(); +} + +CON_COMMAND( g15_dumpplayer, "Spew player data." ) +{ + if ( !CommandLine()->FindParm( "-g15" ) ) + { + Msg( "Must run with -g15 to enable support for the LCD Keyboard\n" ); + return; + } + + gLCD.DumpPlayer(); +} + +static ConVar g15_update_msec( "g15_update_msec", "250", FCVAR_ARCHIVE, "Logitech G-15 Keyboard update interval." ); + +void CLCDItem::Wipe( IG15 *lcd ) +{ + for ( int i = 0; i < m_Children.Count(); ++i ) + { + if ( m_Children[ i ]->m_Handle ) + { + lcd->RemoveAndDestroyObject( m_Children[ i ]->m_Handle ); + } + + m_Children[ i ]->Wipe( lcd ); + + delete m_Children[ i ]; + } + + m_Children.Purge(); + +} +void CLCDItemAggregate::Create( IG15 *lcd ) +{ + // Nothing +} + +void CLCDItemAggregate::Wipe( IG15 *lcd ) +{ + BaseClass::Wipe( lcd ); + + for ( int i = 0; i < m_Definition.Count(); ++i ) + { + m_Definition[ i ]->Wipe( lcd ); + + delete m_Definition[ i ]; + } + + m_Definition.Purge(); +} + +void CLCDItemAggregate::WipeChildrenOnly( IG15 *lcd ) +{ + BaseClass::Wipe( lcd ); +} + +void CLCDItemIcon::Create( IG15 *lcd ) +{ +#ifdef WIN32 + m_Handle = lcd->AddIcon( (HICON)m_icon, w, h ); +#else + m_Handle = lcd->AddIcon( (void *)m_icon, w, h ); +#endif + lcd->SetOrigin( m_Handle, x, y ); + lcd->SetVisible( m_Handle, false ); +} + +void CLCDItemText::Create( IG15 *lcd ) +{ + m_Handle = lcd->AddText( G15_STATIC_TEXT, (G15TextSize)m_iSize, m_iAlign, w ); + lcd->SetOrigin( m_Handle, x, y ); + lcd->SetText( m_Handle, m_OriginalText ); + lcd->SetVisible( m_Handle, false ); +} + + +///----------------------------------------------------------------------------- +/// Constructor +///----------------------------------------------------------------------------- +CLCD::CLCD( void ) + : m_lcd( NULL ), + m_nCurrentPage( 0 ), + m_nSubPage( 0 ), + m_bHadPlayer( false ), + m_dwNextUpdateTime( 0u ), + m_nMaxChatHistory( G15_DEFAULT_MAX_CHAT_HISTORY ), + m_pG15Module( 0 ), + m_G15Factory( 0 ) +{ + m_Size[ 0 ] = m_Size[ 1 ] = 0; +} + +///----------------------------------------------------------------------------- +/// Destructor +///----------------------------------------------------------------------------- +CLCD::~CLCD( void ) +{ +} + +void CLCD::Reload() +{ + Shutdown(); + + Msg( "Reloading G15 config\n" ); + + Init(); +} + +///------------------------------------------------------------------------------ +/// Initializes the LCD device, and sets up the text handles +///------------------------------------------------------------------------------ +void CLCD::Init( void ) +{ + if ( !CommandLine()->FindParm( "-g15" ) ) + return; + + if ( m_lcd ) + return; + + m_pG15Module = Sys_LoadModule( G15_MODULE_NAME ); + if ( !m_pG15Module ) + { + return; + } + + m_G15Factory = Sys_GetFactory( m_pG15Module ); + if ( !m_G15Factory ) + { + Shutdown(); + return; + } + + m_lcd = reinterpret_cast< IG15 * >( m_G15Factory( G15_INTERFACE_VERSION, NULL ) ); + if ( !m_lcd ) + { + Shutdown(); + return; + } + + m_lcd->GetLCDSize( m_Size[ 0 ], m_Size[ 1 ] ); + + m_nCurrentPage = 0; + m_nSubPage = 0; + + m_TextSizes.Insert( "small", G15_SMALL ); + m_TextSizes.Insert( "medium", G15_MEDIUM ); + m_TextSizes.Insert( "big", G15_BIG ); + + m_TextAlignments.Insert( "left", DT_LEFT ); + m_TextAlignments.Insert( "center", DT_CENTER ); + m_TextAlignments.Insert( "right", DT_RIGHT ); + + KeyValues *kv = new KeyValues( "G15" ); + if ( kv->LoadFromFile( filesystem, G15_RESOURCE_FILE, "MOD" ) ) + { + char const *title = kv->GetString( "game", "Source Engine" ); + m_nMaxChatHistory = clamp( 1, kv->GetInt( "chatlines", m_nMaxChatHistory ), 64 ); + Assert( title ); + m_Title = title; + m_lcd->Init( m_Title.String() ); + + for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) + { + char const *keyName = sub->GetName(); + if ( !Q_stricmp( keyName, "game" ) ) + { + // Handled above!!! + } + else if ( !Q_stricmp( keyName, "icons" ) ) + { + ParseIconMappings( sub ); + } + else if ( !Q_stricmp( keyName, "replace" ) ) + { + ParseReplacements( sub ); + } + else if ( !Q_stricmp( keyName, "page" ) ) + { + ParsePage( sub ); + } + } + } + kv->deleteThis(); + + UpdateChat(); + + Msg( "Logitech LCD Keyboard initialized\n" ); +} + +///-------------------------------------------------------------------------- +/// Destroys the local EZ LCD Object +///-------------------------------------------------------------------------- +void CLCD::Shutdown( void ) +{ + for ( int i = 0; i < m_Pages.Count(); ++i ) + { + CLCDPage *page = m_Pages[ i ]; + page->Wipe( m_lcd ); + delete page; + } + + m_Pages.Purge(); + + if ( m_lcd ) + { + m_lcd->Shutdown(); + m_lcd = NULL; + } + + m_TextSizes.Purge(); + m_TextAlignments.Purge(); + m_GlobalStats.Purge(); + + m_G15Factory = 0; + + if ( m_pG15Module ) + { + Sys_UnloadModule( m_pG15Module ); + m_pG15Module = 0; + } +} + +int CLCD::FindTitlePage() +{ + for ( int i = 0; i < m_Pages.Count(); ++i ) + { + if ( m_Pages[ i ]->m_bTitlePage ) + return i; + } + + return -1; +} + +bool CLCD::IsPageValid( int currentPage, C_BasePlayer *player ) +{ + if ( m_Pages[ currentPage ]->m_bTitlePage && player ) + return false; + + if ( m_Pages[ currentPage ]->m_bRequiresPlayer && !player ) + return false; + + return true; +} + +///--------------------------------------------------------------------- +/// Update routine +///--------------------------------------------------------------------- +void CLCD::Update( void ) +{ + if ( !m_lcd ) + return ; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + bool hasplayer = player ? true : false; + + bool changed = hasplayer != m_bHadPlayer; + m_bHadPlayer = hasplayer; + + int pageCount = m_Pages.Count(); + + int prevPage = m_nCurrentPage; + + if ( pageCount > 0 ) + { + bool force = false; + if ( changed && hasplayer ) + { + force = true; + m_nCurrentPage = 0; + m_nSubPage = 0; + } + + if ( !IsPageValid( m_nCurrentPage, player ) ) + { + force = true; + } + + if ( m_lcd->ButtonTriggered( G15_BUTTON_1 ) || force ) + { + m_nSubPage = 0; + + for ( int i = 0; i < pageCount; ++i ) + { + m_nCurrentPage = ( m_nCurrentPage + 1 ) % pageCount; + if ( !IsPageValid( m_nCurrentPage, player ) ) + continue; + + + + break; + } + } + + if ( m_lcd->ButtonTriggered( G15_BUTTON_2 ) ) + { + int pc = m_Pages[ m_nCurrentPage ]->m_nSubPageCount; + + m_nSubPage = ( m_nSubPage + 1 ) % pc; + } + } + else + { + m_nCurrentPage = -1; + m_nSubPage = 0; + } + + bool pageChanged = prevPage != m_nCurrentPage; + + unsigned int dwCurTime = (unsigned int)( 1000.0 * gpGlobals->realtime ); + + if ( m_lcd->IsConnected() ) + { + if ( dwCurTime >= m_dwNextUpdateTime || pageChanged ) + { + m_dwNextUpdateTime = dwCurTime + g15_update_msec.GetInt(); + DisplayCurrentPage( dwCurTime ); + } + } + + m_lcd->UpdateLCD( dwCurTime ); +} + +///-------------------------------------------------------------------------- +/// +///-------------------------------------------------------------------------- +bool CLCD::IsConnected( void ) const +{ + return m_lcd ? m_lcd->IsConnected() : false; +} + +void CLCD::ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCDItem * >& list, bool bShowItems ) +{ + int itemCount = list.Count(); + for ( int j = 0; j < itemCount; ++j ) + { + CLCDItem *item = list[ j ]; + if ( !item->m_bActive ) + continue; + + if ( bShowItems ) + { + switch ( item->m_Type ) + { + default: + break; + case LCDITEM_TEXT: + { + CLCDItemText *txt = static_cast< CLCDItemText * >( item ); + if ( txt ) + { + // Need to build updated text + CUtlString updated; + CUtlString str = txt->m_OriginalText; + BuildUpdatedText( str.String(), updated ); + DoGlobalReplacements( updated ); + ReduceParentheses( updated ); + + m_lcd->SetText( item->m_Handle, updated.String() ); + } + } + break; + case LCDITEM_ICON: + { + CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( item ); + if ( icon ) + { + // Need to build updated text + CUtlString updated; + CUtlString str = icon->m_IconName; + BuildUpdatedText( str.String(), updated ); + DoGlobalReplacements( updated ); + ReduceParentheses( updated ); + + int idx = m_Icons.Find( updated.String() ); + if ( idx != m_Icons.InvalidIndex() ) + { + icon->m_icon = (void *)m_Icons[ idx ].m_handle; + } + + // Recreate + if ( icon->m_Handle ) + { + m_lcd->RemoveAndDestroyObject( icon->m_Handle ); + icon->m_Handle = 0; + } + icon->Create( m_lcd ); + } + } + break; + case LCDITEM_AGGREGATE: + { + CLCDItemAggregate *ag = static_cast< CLCDItemAggregate * >( item ); + if ( ag->m_dwNextUpdateTime > dwCurTime ) + break; + + // FIXME: encode update interval in text file + ag->m_dwNextUpdateTime = dwCurTime + 1000; + + // Blow away current data + ag->WipeChildrenOnly( m_lcd ); + + CUtlVector< int > validIndices; + char prefix[ 256 ]; + char altprefix[ 256 ]; + prefix[ 0 ] = 0; + altprefix[ 0 ] = 0; + + int curx = ag->x; + int cury = ag->y; + + switch ( ag->m_AggType ) + { + default: + Assert( 0 ); + break; + case AGGTYPE_PERPLAYER: + // Add all players into list + { + for ( int pl = 1; pl <= gpGlobals->maxClients; ++pl ) + { + if ( g_PR && g_PR->IsConnected( pl ) ) + { + validIndices.AddToTail( pl ); + } + } + + Q_strncpy( prefix, "(playerindex)", sizeof( prefix ) ); + Q_strncpy( altprefix, "(playerindexplusone)", sizeof( altprefix ) ); + } + break; + case AGGTYPE_PERTEAM: + { + C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); + + if ( local ) + { + for ( int pl = 1; pl <= gpGlobals->maxClients; ++pl ) + { + if ( g_PR && g_PR->IsConnected( pl ) && local->GetTeamNumber() == g_PR->GetTeam( pl ) ) + { + validIndices.AddToTail( pl ); + } + } + } + + Q_strncpy( prefix, "(playerindex)", sizeof( prefix ) ); + Q_strncpy( altprefix, "(playerindexplusone)", sizeof( altprefix ) ); + } + break; + } + + int subPage = 0; + int spItems = 0; + + int ecount = validIndices.Count(); + for ( int e = 0; e < ecount; ++e ) + { + // Now fixup any strings + int index = validIndices[ e ]; + + char s1[ 512 ], s2[ 512 ]; + Q_snprintf( s1, sizeof( s1 ), "%d", index ); + Q_snprintf( s2, sizeof( s2 ), "%d", index + 1 ); + + // Now replace "playerindex" with the index as needed + for( int r = 0; r < ag->m_Definition.Count(); ++r ) + { + CLCDItem *newItem = NULL; + + CLCDItem *item = ag->m_Definition[ r ]; + switch ( item->m_Type ) + { + default: + break; + + case LCDITEM_TEXT: + { + CLCDItemText *text = static_cast< CLCDItemText * >( item ); + CUtlString s; + s = text->m_OriginalText; + Replace( s, prefix, s1 ); + Replace( s, altprefix, s2 ); + char itemNumber[ 32 ]; + Q_snprintf( itemNumber, sizeof( itemNumber ), "%d", e +1 ); + + Replace( s, "(itemnumber)", itemNumber ); + + DoGlobalReplacements( s ); + // ReduceParentheses( s ); + + // text->m_OriginalText = s; + + CLCDItemText *copy = static_cast< CLCDItemText * >( page->Alloc( item->m_Type ) ); + *copy = *text; + copy->m_bActive = true; + copy->m_OriginalText = s; + copy->Create( m_lcd ); + + m_lcd->SetOrigin( copy->m_Handle, curx + copy->x, cury + copy->y ); + + newItem = copy; + } + break; + case LCDITEM_ICON: + { + CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( item ); + CLCDItemIcon *copy = static_cast< CLCDItemIcon * >( page->Alloc( item->m_Type ) ); + *copy = *icon; + copy->m_bActive = true; + copy->Create( m_lcd ); + + m_lcd->SetOrigin( copy->m_Handle, curx + copy->x, cury + copy->y ); + + newItem = copy; + } + break; + } + + if ( newItem ) + { + ++spItems; + newItem->m_nSubPage = subPage; + ag->m_Children.AddToTail( newItem ); + } + } + + cury += ag->m_yincrement; + + if ( cury + SMALL_ITEM_HEIGHT > m_Size[ 1 ] ) + { + spItems = 0; + ++subPage; + cury = ag->y; + } + } + + if ( spItems > 0 ) + { + page->m_nSubPageCount = subPage + 1; + } + else + { + // We thought we needed a new page, but didn't actually use it + page->m_nSubPageCount = subPage; + } + } + } + } + + m_lcd->SetVisible( item->m_Handle, bShowItems && ( ( item->m_nSubPage == -1 ) || item->m_nSubPage == m_nSubPage ) ); + + ShowItems_R( page, dwCurTime, item->m_Children, bShowItems ); + } +} + +void CLCD::DisplayCurrentPage( unsigned int dwCurTime ) +{ + int pageCount = m_Pages.Count(); + for ( int i = 0; i < pageCount; ++i ) + { + bool bShowItems = ( i == m_nCurrentPage ) ? true : false; + + CLCDPage* page = m_Pages[ i ]; + ShowItems_R( page, dwCurTime, page->m_Children, bShowItems ); + } +} + +CLCDItemIcon *CLCD::ParseItemIcon( CLCDPage *page, bool bCreateHandles, KeyValues *sub ) +{ + CLCDItemIcon *item = static_cast< CLCDItemIcon * >( page->Alloc( LCDITEM_ICON ) ); + + item->m_IconName = sub->GetString( "name", "" ); + + item->m_nSubPage = sub->GetInt( "header", 0 ) ? -1 : page->m_nSubPageCount - 1; + item->w = sub->GetInt( "w", 24 ); + item->h = sub->GetInt( "h", 24 ); + item->x = sub->GetInt( "x", 0 ); + item->y = sub->GetInt( "y", 0 ); + + int idx = m_Icons.Find( item->m_IconName.String() ); + item->m_icon = 0; + if ( idx != m_Icons.InvalidIndex() ) + { + item->m_icon = (void *)m_Icons[ idx ].m_handle; + } + + if ( bCreateHandles ) + { + item->Create( m_lcd ); + } + + return item; +} + +CLCDItemText *CLCD::ParseItemText( CLCDPage *page, bool bCreateHandles, KeyValues *sub ) +{ + CLCDItemText *item = static_cast< CLCDItemText * >( page->Alloc( LCDITEM_TEXT ) ); + + const char *initialText = sub->GetString( "text", "" ); + item->m_bHasWildcard = Q_strstr( initialText, "%" ) ? true : false; + + item->m_nSubPage = sub->GetInt( "header", 0 ) ? -1 : page->m_nSubPageCount - 1; + item->w = sub->GetInt( "w", 150 ); + item->x = sub->GetInt( "x", 0 ); + item->y = sub->GetInt( "y", 0 ); + + const char *sizeStr = sub->GetString( "size", "small" ); + item->m_iSize = G15_SMALL; + int iFound = m_TextSizes.Find( sizeStr ); + if ( iFound != m_TextSizes.InvalidIndex() ) + { + item->m_iSize = m_TextSizes[ iFound ]; + } + + const char *alignStr = sub->GetString( "align", "left" ); + item->m_iAlign = DT_LEFT; + iFound = m_TextAlignments.Find( alignStr ); + if ( iFound != m_TextAlignments.InvalidIndex() ) + { + item->m_iAlign = m_TextAlignments[ iFound ]; + } + + item->m_OriginalText = initialText; + if ( bCreateHandles ) + { + item->Create( m_lcd ); + } + + return item; +} + +void CLCD::ParseItems_R( CLCDPage *page, bool bCreateHandles, KeyValues *kv, CUtlVector< CLCDItem * >& list ) +{ + for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) + { + char const *keyName = sub->GetName(); + if ( !Q_stricmp( keyName, "iterate_players" ) || + !Q_stricmp( keyName, "iterate_team" ) ) + { + int aggType = AGGTYPE_UNKNOWN; + if ( !Q_stricmp( keyName, "iterate_players" ) ) + { + aggType = AGGTYPE_PERPLAYER; + } + else if ( !Q_stricmp( keyName, "iterate_team" ) ) + { + aggType = AGGTYPE_PERTEAM; + } + + // Now we parse the items out as we generally would + CLCDItemAggregate *item = static_cast< CLCDItemAggregate * >( page->Alloc( LCDITEM_AGGREGATE ) ); + item->m_AggType = aggType; + + item->x = sub->GetInt( "x", 0 ); + item->y = sub->GetInt( "y", 0 ); + item->m_yincrement = sub->GetInt( "y_increment", 10 ); + + // Parse the definition + ParseItems_R( page, false, sub, item->m_Definition ); + + // Add the definition items as "inactive" items to the scene (so they get destroyed) + for ( int i = 0; i < item->m_Definition.Count(); ++i ) + { + CLCDItem *pItem = item->m_Definition[ i ]; + pItem->m_bActive = false; + } + + list.AddToTail( item ); + } + else if ( !Q_stricmp( keyName, "static_icon" ) ) + { + CLCDItemIcon *item = ParseItemIcon( page, true, sub ); + Assert( item ); + list.AddToTail(item ); + } + else if ( !Q_stricmp( keyName, "static_text" ) ) + { + CLCDItemText *item = ParseItemText( page, true, sub ); + Assert( item ); + list.AddToTail( item ); + } + else if ( !Q_stricmp( keyName, "newsubpage" ) ) + { + // Add to new subpage + ++page->m_nSubPageCount; + } + else + { + // Skip unknown stuff + continue; + } + } +} + +void CLCD::ParsePage( KeyValues *kv ) +{ + CLCDPage *newPage = new CLCDPage(); + m_Pages.AddToTail( newPage ); + + newPage->m_bTitlePage = kv->GetInt( "titlepage", 0 ) ? true : false; + newPage->m_bRequiresPlayer = kv->GetInt( "requiresplayer", 0 ) ? true : false; + + ParseItems_R( newPage, true, kv, newPage->m_Children ); +} + +void CLCD::ParseIconMappings( KeyValues *kv ) +{ + for ( KeyValues *icon = kv->GetFirstSubKey(); icon; icon = icon->GetNextKey() ) + { + IconInfo_t info; + HICON hIcon = 0; + char const *name = icon->GetName(); + char fullpath[ 512 ]; + filesystem->RelativePathToFullPath( icon->GetString(), "GAME", fullpath, sizeof( fullpath ) ); +#ifdef WIN32 + hIcon = (HICON)::LoadImageA( NULL, fullpath, IMAGE_ICON, 32, 32, LR_LOADFROMFILE ); +#else + hIcon = 0; +#endif + info.m_handle = (void *)hIcon; + m_Icons.Insert( name, info ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Simply dumps all data fields in object +//----------------------------------------------------------------------------- +class CDescribeData +{ +public: + CDescribeData( void const *src ); + + void DescribeShort( const short *invalue, int count ); + void DescribeInt( const int *invalue, int count ); + void DescribeBool( const bool *invalue, int count ); + void DescribeFloat( const float *invalue, int count ); + void DescribeSimpleString( const char *indata, int length ); + void DescribeString( const string_t *instring, int count ); + void DescribeVector( const Vector *inValue, int count ); + void DescribeColor( const Color *invalue, int count ); + void DumpDescription( datamap_t *pMap ); + + void GetValueForField( char const *fieldName, char *buf, size_t bufsize ); + +private: + void DescribeFields_R( int chain_count, datamap_t *pMap, typedescription_t *pFields, int fieldCount ); + bool BuildFieldPath( CUtlString& path ); + + void const *m_pSrc; + int m_nSrcOffsetIndex; + + void Describe( const char *fmt, ... ); + + typedescription_t *m_pCurrentField; + char const *m_pCurrentClassName; + datamap_t *m_pCurrentMap; + + CUtlVector< CUtlString > m_FieldPath; +}; + +CDescribeData::CDescribeData( void const *src ) +{ + m_pSrc = src; + m_nSrcOffsetIndex = TD_OFFSET_NORMAL; + + m_pCurrentField = NULL; + m_pCurrentMap = NULL; + m_pCurrentClassName = NULL; +} + +typedescription_t *FindFieldByName( datamap_t *pMap, char const *fn ) +{ + while ( pMap ) + { + for ( int i = 0; i < pMap->dataNumFields; i++ ) + { + typedescription_t *current = &pMap->dataDesc[ i ]; + if ( !current->fieldName ) + continue; + + if ( !Q_stricmp( current->fieldName, fn ) ) + return current; + } + + pMap = pMap->baseMap; + } + + return NULL; +} + +typedescription_t *FindField( datamap_t *pMap, char const *relativePath ) +{ + if ( !Q_strstr( relativePath, "." ) ) + { + // Simple case, just look up field name + return FindFieldByName( pMap, relativePath ); + } + + // Complex case + + Assert( 0 ); + return NULL; +} + +bool CDescribeData::BuildFieldPath( CUtlString& path ) +{ + int c = m_FieldPath.Count(); + if ( c == 0 ) + return false; + + for ( int i = 0; i < c; ++i ) + { + CUtlString& s = m_FieldPath[ i ]; + if ( i != 0 ) + { + path += "."; + } + path += s; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *fmt - +// ... - +//----------------------------------------------------------------------------- +void CDescribeData::Describe( const char *fmt, ... ) +{ + Assert( m_pCurrentMap ); + Assert( m_pCurrentClassName ); + + const char *fieldname = "empty"; + + if ( m_pCurrentField ) + { + fieldname = m_pCurrentField->fieldName ? m_pCurrentField->fieldName : "NULL"; + } + + va_list argptr; + char data[ 4096 ]; + int len; + va_start(argptr, fmt); + len = Q_vsnprintf(data, sizeof( data ), fmt, argptr); + va_end(argptr); + + CUtlString fp; + if ( BuildFieldPath( fp ) ) + { + Msg( "%s.%s%s", + fp.String(), + fieldname, + data ); + } + else + { + Msg( "%s%s", + fieldname, + data ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : size - +// *outdata - +// *indata - +//----------------------------------------------------------------------------- +void CDescribeData::DescribeSimpleString( char const *invalue, int count ) +{ + Describe( "%s\n", invalue ? invalue : "" ); +} + + +void CDescribeData::DescribeShort( const short *invalue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " short (%i)\n", (int)(invalue[i]) ); + } + else + { + Describe( "[%i] short (%i)\n", i, (int)(invalue[i]) ); + } + } +} + + +void CDescribeData::DescribeInt( const int *invalue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " integer (%i)\n", invalue[i] ); + } + else + { + Describe( "[%i] integer (%i)\n", i, invalue[i] ); + } + } +} + +void CDescribeData::DescribeBool( const bool *invalue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " bool (%s)\n", (invalue[i]) ? "true" : "false" ); + } + else + { + Describe( "[%i] bool (%s)\n", i, (invalue[i]) ? "true" : "false" ); + } + } +} + +void CDescribeData::DescribeFloat( const float *invalue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " float (%f)\n", invalue[ i ] ); + } + else + { + Describe( "[%i] float (%f)\n", i, invalue[ i ] ); + } + } +} + +void CDescribeData::DescribeString( const string_t *instring, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " string (%s)\n", instring[ i ] ? instring[ i ] : "" ); + } + else + { + Describe( "[%i] string (%s)\n", i, instring[ i ] ? instring[ i ] : "" ); + } + } +} + +void CDescribeData::DescribeColor( const Color *invalue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " color (%i %i %i %i)\n", invalue[ i ].r(), invalue[ i ].g(), invalue[ i ].b(), invalue[ i ].a() ); + } + else + { + Describe( "[%i] color (%i %i %i %i)\n", i, invalue[ i ].r(), invalue[ i ].g(), invalue[ i ].b(), invalue[ i ].a() ); + } + } +} + +void CDescribeData::DescribeVector( const Vector *inValue, int count ) +{ + for ( int i = 0; i < count; ++i ) + { + if ( count == 1 ) + { + Describe( " vector (%f %f %f)\n", + inValue[i].x, inValue[i].y, inValue[i].z ); + } + else + { + Describe( "[%i] vector (%f %f %f)\n", + i, + inValue[i].x, inValue[i].y, inValue[i].z ); + } + } +} + +void CDescribeData::DescribeFields_R( int chain_count, datamap_t *pRootMap, typedescription_t *pFields, int fieldCount ) +{ + int i; + int flags; + int fieldOffsetSrc; + int fieldSize; + + m_pCurrentMap = pRootMap; + if ( !m_pCurrentClassName ) + { + m_pCurrentClassName = pRootMap->dataClassName; + } + + for ( i = 0; i < fieldCount; i++ ) + { + m_pCurrentField = &pFields[ i ]; + flags = m_pCurrentField->flags; + + // Skip this field + if ( flags & FTYPEDESC_VIEW_NEVER ) + continue; + + // Mark any subchains first + if ( m_pCurrentField->override_field != NULL ) + { + m_pCurrentField->override_field->override_count = chain_count; + } + + // Skip this field? + if ( m_pCurrentField->override_count == chain_count ) + { + continue; + } + + void const *pInputData; + + fieldOffsetSrc = m_pCurrentField->fieldOffset[ m_nSrcOffsetIndex ]; + fieldSize = m_pCurrentField->fieldSize; + + pInputData = (void const *)((char *)m_pSrc + fieldOffsetSrc ); + + switch( m_pCurrentField->fieldType ) + { + default: + break; + case FIELD_EMBEDDED: + { + typedescription_t *save = m_pCurrentField; + void const *saveSrc = m_pSrc; + const char *saveName = m_pCurrentClassName; + + m_pCurrentClassName = m_pCurrentField->td->dataClassName; + + CUtlString str; + str = m_pCurrentField->fieldName; + + m_FieldPath.AddToTail( str ); + + m_pSrc = pInputData; + if ( ( flags & FTYPEDESC_PTR ) && (m_nSrcOffsetIndex == PC_DATA_NORMAL) ) + { + m_pSrc = *((void**)m_pSrc); + } + + DescribeFields_R( chain_count, pRootMap, m_pCurrentField->td->dataDesc, m_pCurrentField->td->dataNumFields ); + + m_FieldPath.Remove( m_FieldPath.Count() - 1 ); + + m_pCurrentClassName = saveName; + m_pCurrentField = save; + m_pSrc = saveSrc; + } + break; + case FIELD_FLOAT: + DescribeFloat( (float const *)pInputData, fieldSize ); + break; + case FIELD_STRING: + DescribeString( (const string_t*)pInputData, fieldSize ); + break; + case FIELD_VECTOR: + DescribeVector( (const Vector *)pInputData, fieldSize ); + break; + case FIELD_COLOR32: + DescribeColor( (const Color *)pInputData, fieldSize ); + break; + + case FIELD_BOOLEAN: + DescribeBool( (bool const *)pInputData, fieldSize ); + break; + case FIELD_INTEGER: + DescribeInt( (int const *)pInputData, fieldSize ); + break; + + case FIELD_SHORT: + DescribeShort( (short const *)pInputData, fieldSize ); + break; + + case FIELD_CHARACTER: + DescribeSimpleString( (const char *)pInputData, fieldSize ); + break; + } + } + + m_pCurrentClassName = NULL; +} + +static int g_nChainCount = 1; +extern void ValidateChains_R( datamap_t *dmap ); + +void CDescribeData::DumpDescription( datamap_t *pMap ) +{ + ++g_nChainCount; + + if ( !pMap->chains_validated ) + { + ValidateChains_R( pMap ); + } + + while ( pMap ) + { + DescribeFields_R( g_nChainCount, pMap, pMap->dataDesc, pMap->dataNumFields ); + + pMap = pMap->baseMap; + } +} + + +void CLCD::DumpPlayer() +{ + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + return; + + Msg( "(localplayer)\n\n" ); + + CDescribeData helper( player ); + helper.DumpDescription( player->GetPredDescMap() ); + + Msg( "(localteam)\n\n" ); + + C_Team *team = player->GetTeam(); + if ( team ) + { + CDescribeData helper( team ); + helper.DumpDescription( team->GetPredDescMap() ); + } + + Msg( "(playerresource)\n\n" ); + + if ( g_PR ) + { + CDescribeData helper( g_PR ); + helper.DumpDescription( g_PR->GetPredDescMap() ); + } + + Msg( "(localplayerweapon)\n\n" ); + // Get the player's weapons, too + C_BaseCombatWeapon *active = player->GetActiveWeapon(); + if ( active ) + { + CDescribeData helper( active ); + helper.DumpDescription( active->GetPredDescMap() ); + } + + Msg( "Other replacements:\n\n" ); + + // Global replacements + for( int i = m_GlobalStats.First() ; i != m_GlobalStats.InvalidIndex(); i = m_GlobalStats.Next( i ) ) + { + CUtlString& r = m_GlobalStats[ i ]; + + char const *pReplace = r.String(); + char ansi[ 512 ]; + ansi[ 0 ] = 0; + + if ( pReplace[ 0 ] == '#' ) + { + const wchar_t *pWString = g_pVGuiLocalize->Find( pReplace ); + if ( pWString ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pWString, ansi, sizeof( ansi ) ); + pReplace = ansi; + } + } + + Msg( "'%s' = '%s'\n", m_GlobalStats.GetElementName( i ), pReplace ); + } +} + +bool CLCD::ExtractArrayIndex( char *str, size_t bufsize, int *index ) +{ + Assert( index ); + *index = 0; + + char s[ 2048 ]; + Q_strncpy( s, str, sizeof( s ) ); + + char *pos = Q_strstr( s, "[" ); + if ( !pos ) + return false; + + char *pos2 = Q_strstr( s, "]" ); + if ( !pos2 ) + return false; + + char num[ 32 ]; + Q_strncpy( num, pos + 1, pos2 - pos ); + *index = Q_atoi( num ); + + int left = pos - s + 1; + char o[ 2048 ]; + Q_strncpy( o, s, left ); + Q_strncat( o, pos2 + 1, sizeof( o ), COPY_ALL_CHARACTERS ); + + Q_strncpy( str, o, bufsize ); + return true; +} + +void CLCD::LookupToken( char const *in, CUtlString& value ) +{ + value = ""; + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + if ( !player ) + { + return; + } + + C_BaseEntity *ref = NULL; + + char outbuf[ 1024 ]; + char *o = outbuf; + char const *i = in; + while ( *i ) + { + if ( *i == '(' ) + { + char token[ 512 ]; + char *to = token; + // swallow everything until matching '%' character + ++i; + while ( *i && *i != ')' ) + { + *to++ = *i++; + } + + if ( *i ) + ++i; + + *to = 0; + + if ( !Q_stricmp( token, "localplayer" ) ) + { + ref = player; + } + else if ( !Q_stricmp( token, "localteam" ) ) + { + ref = player->GetTeam(); + } + else if ( !Q_stricmp( token, "localplayerweapon" ) ) + { + ref = player->GetActiveWeapon(); + } + else if ( !Q_stricmp( token, "playerresource" ) ) + { + ref = g_PR; + } + } + else + { + *o++ = *i++; + } + } + + *o = '\0'; + + // Fixme, also need to get array reference removed from end and do the . field searching stuff + + // Outbuf now has the actual field + if ( !ref ) + { + return; + } + + int iIndex = 0; + ExtractArrayIndex( outbuf, sizeof( outbuf ), &iIndex ); + + typedescription_t *td = FindField( ref->GetPredDescMap(), outbuf ); + if ( !td ) + { + return; + } + + // Not allowed to see this one + if ( td->flags & FTYPEDESC_VIEW_NEVER ) + { + return; + } + + int fieldOffsetSrc = td->fieldOffset[ TD_OFFSET_NORMAL ]; + // int fieldSize = td->fieldSize; + + void const *pInputData = (void const *)((char *)ref + fieldOffsetSrc ); + + char sz[ 256 ]; + sz[ 0 ] = 0; + // Found it, now get the value + switch ( td->fieldType ) + { + case FIELD_FLOAT: + Q_snprintf( sz, sizeof( sz ), "%.2f", *((float *)pInputData + iIndex ) ); + break; + case FIELD_STRING: + { + string_t *pString = (string_t *)((string_t *)pInputData + iIndex ); + Q_snprintf( sz, sizeof( sz ), "%s", pString ? STRING( *pString ) : "" ); + } + break; + case FIELD_VECTOR: + { + Vector v = *((Vector *)pInputData + iIndex ); + Q_snprintf( sz, sizeof( sz ), "%.2f %.2f %.2f", v.x, v.y, v.z ); + } + break; + case FIELD_COLOR32: + { + Color c = *(( Color * )pInputData + iIndex ); + Q_snprintf( sz, sizeof( sz ), "%d %d %d %d", c.r(), c.g(), c.b(), c.a() ); + } + break; + + case FIELD_BOOLEAN: + Q_snprintf( sz, sizeof( sz ), "%s", *( ( bool *)pInputData + iIndex ) ? "true" : "false" ); + break; + case FIELD_INTEGER: + Q_snprintf( sz, sizeof( sz ), "%i", *( (int *)pInputData + iIndex )); + break; + + case FIELD_SHORT: + Q_snprintf( sz, sizeof( sz ), "%i", *( (short *)pInputData + iIndex ) ); + break; + + case FIELD_CHARACTER: + Q_snprintf( sz, sizeof( sz ), "%s", ((const char *)pInputData + iIndex ) ); + break; + } + + value = sz; +} + +void CLCD::BuildUpdatedText( char const *in, CUtlString& out ) +{ + char outbuf[ 1024 ]; + char *o = outbuf; + char const *i = in; + while ( *i ) + { + if ( *i == '%' ) + { + char token[ 512 ]; + char *to = token; + // swallow everything until matching '%' character + ++i; + while ( *i && *i != '%' ) + { + *to++ = *i++; + } + + if ( *i ) + ++i; + + *to = 0; + + // Now we have the token, do the lookup + CUtlString value; + LookupToken( token, value ); + + to = (char *)value.String(); + while ( *to ) + { + *o++ = *to++; + } + } + else + { + *o++ = *i++; + } + } + + *o = '\0'; + + out = outbuf; +} + + +bool CLCD::Replace( CUtlString& str, char const *search, char const *replace ) +{ + // If search string is part of replacement, this is a bad thing!!! + Assert( !*replace || !Q_strstr( replace, search ) ); + + bool changed = false; + if ( !Q_strstr( str.String(), search ) ) + return false; + + char s[ 2048 ]; + Q_strncpy( s, str.String(), sizeof( s ) ); + + int searchlen = Q_strlen( search ); + while ( true ) + { + char *pos = Q_strstr( s, search ); + if ( !pos ) + break; + + char temp[ 4096 ]; + // Found an instance + int left = pos - s + 1; + Assert( left < sizeof( temp ) ); + Q_strncpy( temp, s, left ); + Q_strncat( temp, replace, sizeof( temp ), COPY_ALL_CHARACTERS ); + int rightofs = left + searchlen - 1; + Q_strncat( temp, &s[ rightofs ], sizeof( temp ), COPY_ALL_CHARACTERS ); + + // Replace entire string + Q_strncpy( s, temp, sizeof( s ) ); + changed = true; + } + + str = s; + + return changed; +} + +void CLCD::SetGlobalStat( char const *name, char const *value ) +{ + if ( !m_lcd ) + return; + + int idx = m_GlobalStats.Find( name ); + if ( idx == m_GlobalStats.InvalidIndex() ) + { + idx = m_GlobalStats.Insert( name ); + } + + m_GlobalStats[ idx ] = value; +} + +void CLCD::AddChatLine( char const *txt ) +{ + if ( !m_lcd ) + return; + + while ( m_ChatHistory.Count() >= m_nMaxChatHistory ) + { + m_ChatHistory.Remove( 0 ); + } + + m_ChatHistory.AddToTail( CUtlString( txt ) ); + + UpdateChat(); +} + +void CLCD::UpdateChat() +{ + for ( int i = 0; i < m_nMaxChatHistory; ++i ) + { + char name[ 32 ]; + Q_snprintf( name, sizeof( name ), "chat_%d", i + 1 ); + + SetGlobalStat( name, i < m_ChatHistory.Count() ? m_ChatHistory[ i ].String() : " " ); + } +} + +void CLCD::DoGlobalReplacements( CUtlString& str ) +{ + // Put some limit to avoid infinite recursion + int maxChanges = 16; + + bool changed = false; + do + { + changed = false; + for ( int i = m_GlobalStats.First(); i != m_GlobalStats.InvalidIndex(); i = m_GlobalStats.Next( i ) ) + { + CUtlString &r = m_GlobalStats[ i ]; + + char const *pReplace = r.String(); + char ansi[ 512 ]; + ansi[ 0 ] = 0; + + if ( pReplace[ 0 ] == '#' ) + { + const wchar_t *pWString = g_pVGuiLocalize->Find( pReplace ); + if ( pWString ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pWString, ansi, sizeof( ansi ) ); + pReplace = ansi; + } + } + + if ( Replace( str, m_GlobalStats.GetElementName( i ), pReplace ) ) + { + changed = true; + } + } + } while ( changed && --maxChanges >= 0 ); +} + +void CLCD::ReduceParentheses( CUtlString& str ) +{ + char s[ 2048 ]; + Q_strncpy( s, str.String(), sizeof( s ) ); + + while ( true ) + { + char *pos = Q_strstr( s, "(" ); + if ( !pos ) + break; + + char *end = Q_strstr( pos, ")" ); + if ( !end ) + break; + + char temp[ 4096 ]; + // Found an instance + int left = pos - s + 1; + Assert( left < sizeof( temp ) ); + Q_strncpy( temp, s, left ); + int rightofs = end - s + 1; + Q_strncat( temp, &s[ rightofs ], sizeof( temp ), COPY_ALL_CHARACTERS ); + + // Replace entire string + Q_strncpy( s, temp, sizeof( s ) ); + } + + str = s; +} + +void CLCD::ParseReplacements( KeyValues *kv ) +{ + for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) + { + char const *key = sub->GetName(); + char const *value = sub->GetString(); + + SetGlobalStat( key, value ); + } +} |