summaryrefslogtreecommitdiff
path: root/game/client/cstrike/VGUI
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/cstrike/VGUI')
-rw-r--r--game/client/cstrike/VGUI/achievement_stats_summary.cpp120
-rw-r--r--game/client/cstrike/VGUI/achievement_stats_summary.h62
-rw-r--r--game/client/cstrike/VGUI/achievements_page.cpp1061
-rw-r--r--game/client/cstrike/VGUI/achievements_page.h218
-rw-r--r--game/client/cstrike/VGUI/backgroundpanel.cpp676
-rw-r--r--game/client/cstrike/VGUI/backgroundpanel.h53
-rw-r--r--game/client/cstrike/VGUI/base_stats_page.cpp359
-rw-r--r--game/client/cstrike/VGUI/base_stats_page.h135
-rw-r--r--game/client/cstrike/VGUI/bordered_panel.cpp27
-rw-r--r--game/client/cstrike/VGUI/bordered_panel.h35
-rw-r--r--game/client/cstrike/VGUI/buymouseoverpanelbutton.h397
-rw-r--r--game/client/cstrike/VGUI/buypreset_imageinfo.cpp577
-rw-r--r--game/client/cstrike/VGUI/buypreset_listbox.cpp406
-rw-r--r--game/client/cstrike/VGUI/buypreset_listbox.h78
-rw-r--r--game/client/cstrike/VGUI/buypreset_panel.cpp447
-rw-r--r--game/client/cstrike/VGUI/buypreset_weaponsetlabel.h302
-rw-r--r--game/client/cstrike/VGUI/career_box.cpp1296
-rw-r--r--game/client/cstrike/VGUI/career_box.h202
-rw-r--r--game/client/cstrike/VGUI/career_button.cpp189
-rw-r--r--game/client/cstrike/VGUI/career_button.h57
-rw-r--r--game/client/cstrike/VGUI/counterstrikeviewport.cpp322
-rw-r--r--game/client/cstrike/VGUI/counterstrikeviewport.h61
-rw-r--r--game/client/cstrike/VGUI/cstrikebuyequipmenu.cpp111
-rw-r--r--game/client/cstrike/VGUI/cstrikebuyequipmenu.h73
-rw-r--r--game/client/cstrike/VGUI/cstrikebuymenu.cpp883
-rw-r--r--game/client/cstrike/VGUI/cstrikebuymenu.h102
-rw-r--r--game/client/cstrike/VGUI/cstrikebuysubmenu.h56
-rw-r--r--game/client/cstrike/VGUI/cstrikeclassmenu.cpp272
-rw-r--r--game/client/cstrike/VGUI/cstrikeclassmenu.h107
-rw-r--r--game/client/cstrike/VGUI/cstrikeclientscoreboard.cpp1596
-rw-r--r--game/client/cstrike/VGUI/cstrikeclientscoreboard.h153
-rw-r--r--game/client/cstrike/VGUI/cstrikespectatorgui.cpp2324
-rw-r--r--game/client/cstrike/VGUI/cstrikespectatorgui.h279
-rw-r--r--game/client/cstrike/VGUI/cstriketeammenu.cpp201
-rw-r--r--game/client/cstrike/VGUI/cstriketeammenu.h54
-rw-r--r--game/client/cstrike/VGUI/cstriketextwindow.cpp146
-rw-r--r--game/client/cstrike/VGUI/cstriketextwindow.h49
-rw-r--r--game/client/cstrike/VGUI/lifetime_stats_page.cpp257
-rw-r--r--game/client/cstrike/VGUI/lifetime_stats_page.h40
-rw-r--r--game/client/cstrike/VGUI/match_stats_page.cpp334
-rw-r--r--game/client/cstrike/VGUI/match_stats_page.h39
-rw-r--r--game/client/cstrike/VGUI/stat_card.cpp106
-rw-r--r--game/client/cstrike/VGUI/stat_card.h49
-rw-r--r--game/client/cstrike/VGUI/stats_summary.cpp684
-rw-r--r--game/client/cstrike/VGUI/stats_summary.h84
-rw-r--r--game/client/cstrike/VGUI/win_panel_round.cpp470
-rw-r--r--game/client/cstrike/VGUI/win_panel_round.h65
47 files changed, 15614 insertions, 0 deletions
diff --git a/game/client/cstrike/VGUI/achievement_stats_summary.cpp b/game/client/cstrike/VGUI/achievement_stats_summary.cpp
new file mode 100644
index 0000000..81ef298
--- /dev/null
+++ b/game/client/cstrike/VGUI/achievement_stats_summary.cpp
@@ -0,0 +1,120 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "achievement_stats_summary.h"
+#include "achievements_page.h"
+#include "lifetime_stats_page.h"
+#include "match_stats_page.h"
+#include "stats_summary.h"
+
+#include <stdio.h>
+
+using namespace vgui;
+
+#include <vgui/ILocalize.h>
+#include "vgui/ISurface.h"
+
+#include "filesystem.h"
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+const int cDialogWidth = 900;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CAchievementAndStatsSummary::CAchievementAndStatsSummary(vgui::Panel *parent) : BaseClass(parent, "AchievementAndStatsSummary")
+{
+ SetDeleteSelfOnClose(false);
+ //SetBounds(0, 0, 640, 384);
+ SetBounds(0, 0, 900, 780);
+ SetMinimumSize( 640, 780 );
+ SetSizeable( false );
+
+ SetTitle("#GameUI_CreateAchievementsAndStats", true);
+ SetOKButtonText("#GameUI_Close");
+ SetCancelButtonVisible(false);
+
+ m_pStatsSummary = new CStatsSummary( this, "StatsSummary" );
+ m_pAchievementsPage = new CAchievementsPage(this, "AchievementsPage");
+ m_pLifetimeStatsPage = new CLifetimeStatsPage(this, "StatsPage");
+ m_pMatchStatsPage = new CMatchStatsPage(this, "MatchStatsPage");
+
+ AddPage(m_pStatsSummary, "#GameUI_Stats_Summary");
+ AddPage(m_pAchievementsPage, "#GameUI_Achievements_Tab");
+ AddPage(m_pMatchStatsPage, "#GameUI_MatchStats");
+ AddPage(m_pLifetimeStatsPage, "#GameUI_LifetimeStats");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CAchievementAndStatsSummary::~CAchievementAndStatsSummary()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementAndStatsSummary::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );
+
+ // [smessick] Close the achievements dialog for a low resolution screen.
+ if ( screenWide < cAchievementsDialogMinWidth )
+ {
+ OnOK( true );
+ Close();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs the server when the OK button is pressed
+//-----------------------------------------------------------------------------
+bool CAchievementAndStatsSummary::OnOK(bool applyOnly)
+{
+ BaseClass::OnOK(applyOnly);
+
+ return true;
+}
+
+//----------------------------------------------------------
+// Purpose: Preserve our width to the one in the .res file
+//----------------------------------------------------------
+void CAchievementAndStatsSummary::OnSizeChanged(int newWide, int newTall)
+{
+ // Lock the width, but allow height scaling
+ if ( newWide != cDialogWidth )
+ {
+ SetSize( cDialogWidth, newTall );
+ return;
+ }
+
+ BaseClass::OnSizeChanged(newWide, newTall);
+}
+
+//----------------------------------------------------------
+// Purpose: Processes when summary dialog is activated.
+//----------------------------------------------------------
+void CAchievementAndStatsSummary::Activate()
+{
+ m_pStatsSummary->MakeReadyForUse();
+ m_pStatsSummary->UpdateStatsData();
+ m_pAchievementsPage->UpdateAchievementDialogInfo();
+ m_pLifetimeStatsPage->UpdateStatsData();
+ m_pMatchStatsPage->UpdateStatsData();
+
+ BaseClass::Activate();
+}
diff --git a/game/client/cstrike/VGUI/achievement_stats_summary.h b/game/client/cstrike/VGUI/achievement_stats_summary.h
new file mode 100644
index 0000000..c73b4d7
--- /dev/null
+++ b/game/client/cstrike/VGUI/achievement_stats_summary.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ACHIEVEMENTANDSTATSSUMMARY_H
+#define ACHIEVEMENTANDSTATSSUMMARY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyDialog.h>
+
+class CAchievementsPage;
+class CLifetimeStatsPage;
+class CMatchStatsPage;
+class StatCard;
+class CStatsSummary;
+
+const int cAchievementsDialogMinWidth = 1024; // don't show this screen for lower resolutions
+
+//-----------------------------------------------------------------------------
+// Purpose: dialog for displaying the achievements/stats summary
+//-----------------------------------------------------------------------------
+class CAchievementAndStatsSummary : public vgui::PropertyDialog
+{
+ DECLARE_CLASS_SIMPLE( CAchievementAndStatsSummary, vgui::PropertyDialog );
+
+public:
+ CAchievementAndStatsSummary(vgui::Panel *parent);
+ ~CAchievementAndStatsSummary();
+
+ virtual void Activate();
+
+ void OnKeyCodePressed( vgui::KeyCode code )
+ {
+ if ( code == KEY_XBUTTON_B )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+protected:
+ virtual bool OnOK(bool applyOnly);
+ virtual void OnSizeChanged( int newWide, int newTall );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+private:
+ CAchievementsPage* m_pAchievementsPage;
+ CLifetimeStatsPage* m_pLifetimeStatsPage;
+ CMatchStatsPage* m_pMatchStatsPage;
+ CStatsSummary* m_pStatsSummary;
+};
+
+
+#endif // ACHIEVEMENTANDSTATSSUMMARY_H
diff --git a/game/client/cstrike/VGUI/achievements_page.cpp b/game/client/cstrike/VGUI/achievements_page.cpp
new file mode 100644
index 0000000..bc6036e
--- /dev/null
+++ b/game/client/cstrike/VGUI/achievements_page.cpp
@@ -0,0 +1,1061 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Display a list of achievements for the current game
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "achievements_page.h"
+#include "vgui_controls/Button.h"
+#include "vgui/ILocalize.h"
+#include "ixboxsystem.h"
+#include "iachievementmgr.h"
+#include "filesystem.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/CheckButton.h"
+#include "fmtstr.h"
+#include "c_cs_playerresource.h"
+#include "stat_card.h"
+#include <vgui/IInput.h>
+
+#include "../../../public/steam/steam_api.h"
+#include "achievementmgr.h"
+#include "../../../../public/vgui/IScheme.h"
+#include "../vgui_controls/ScrollBar.h"
+#include "achievements_cs.h"
+
+extern CAchievementMgr g_AchievementMgrCS;
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+KeyValues *g_pPreloadedCSAchievementPageItemLayout = NULL;
+KeyValues *g_pPreloadedCSAchievementPageGroupLayout = NULL;
+
+// Shared helper functions so xbox and pc can share as much code as possible while coming from different bases.
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
+//-----------------------------------------------------------------------------
+bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement* pAchievement, const char *pszExt /*= NULL*/ )
+{
+ char imagePath[_MAX_PATH];
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
+ if ( pszExt )
+ {
+ Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS );
+ }
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ char checkFile[_MAX_PATH];
+ Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
+ if ( !g_pFullFileSystem->FileExists( checkFile ) )
+ {
+ Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
+ }
+
+ pIconPanel->SetShouldScaleImage( true );
+ pIconPanel->SetImage( imagePath );
+ pIconPanel->SetVisible( true );
+
+ return pIconPanel->IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
+//-----------------------------------------------------------------------------
+bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt /*= NULL*/ )
+{
+ char imagePath[_MAX_PATH];
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS );
+ if ( pszExt )
+ {
+ Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS );
+ }
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ char checkFile[_MAX_PATH];
+ Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
+ if ( !g_pFullFileSystem->FileExists( checkFile ) )
+ {
+ Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
+ }
+
+ pIconPanel->SetShouldScaleImage( true );
+ pIconPanel->SetImage( imagePath );
+ pIconPanel->SetVisible( true );
+
+ return pIconPanel->IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// The bias is to ensure the percentage bar gets plenty orange before it reaches the text,
+// as the white-on-grey is hard to read.
+//-----------------------------------------------------------------------------
+Color CSLerpColorsForPage ( Color cStart, Color cEnd, float flPercent )
+{
+ float r = (float)((float)(cStart.r()) + (float)(cEnd.r() - cStart.r()) * Bias( flPercent, 0.75 ) );
+ float g = (float)((float)(cStart.g()) + (float)(cEnd.g() - cStart.g()) * Bias( flPercent, 0.75 ) );
+ float b = (float)((float)(cStart.b()) + (float)(cEnd.b() - cStart.b()) * Bias( flPercent, 0.75 ) );
+ float a = (float)((float)(cStart.a()) + (float)(cEnd.a() - cStart.a()) * Bias( flPercent, 0.75 ) );
+ return Color( r, g, b, a );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shares common percentage bar calculations/color settings between xbox and pc.
+// Not really intended for robustness or reuse across many panels.
+// Input : pFrame - assumed to have certain child panels (see below)
+// *pAchievement - source achievement to poll for progress. Non progress achievements will not show a percentage bar.
+//-----------------------------------------------------------------------------
+void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement* pAchievement, Color clrProgressBar )
+{
+ ///*
+ if ( pAchievement->GetGoal() > 1 )
+ {
+ bool bShowProgress = true;
+
+ // if this achievement gets saved with game and we're not in a level and have not achieved it, then we do not have any state
+ // for this achievement, don't show progress
+ if ( ( pAchievement->GetFlags() & ACH_SAVE_WITH_GAME ) && /*!GameUI().IsInLevel() &&*/ !pAchievement->IsAchieved() )
+ {
+ bShowProgress = false;
+ }
+
+ float flCompletion = 0.0f;
+
+ // Once achieved, we can't rely on count. If they've completed the achievement just set to 100%.
+ int iCount = pAchievement->GetCount();
+ if ( pAchievement->IsAchieved() )
+ {
+ flCompletion = 1.0f;
+ iCount = pAchievement->GetGoal();
+ }
+ else if ( bShowProgress )
+ {
+ flCompletion = ( ((float)pAchievement->GetCount()) / ((float)pAchievement->GetGoal()) );
+ // In rare cases count can exceed goal and not be achieved (switch local storage on X360, take saved game from different user on PC).
+ // These will self-correct with continued play, but if we're in that state don't show more than 100% achieved.
+ flCompletion = MIN( flCompletion, 1.0 );
+ }
+
+ char szPercentageText[ 256 ] = "";
+ if ( bShowProgress )
+ {
+ Q_snprintf( szPercentageText, 256, "%d/%d", iCount, pAchievement->GetGoal() );
+ }
+
+ pPanel->SetControlString( "PercentageText", szPercentageText );
+ pPanel->SetControlVisible( "PercentageText", true );
+ pPanel->SetControlVisible( "CompletionText", true );
+
+ vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBar" );
+ vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBarBackground" );
+
+ if ( pPercentageBar && pPercentageBarBkg )
+ {
+ pPercentageBar->SetFillColor( clrProgressBar );
+ pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion );
+
+ pPanel->SetControlVisible( "PercentageBarBackground", IsX360() ? bShowProgress : true );
+ pPanel->SetControlVisible( "PercentageBar", true );
+ }
+ }
+ //*/
+}
+
+// TODO: revisit this once other games are rebuilt using the updated IAchievement interface
+bool CSGameSupportsAchievementTrackerForPage()
+{
+ const char *pGame = Q_UnqualifiedFileName( engine->GetGameDirectory() );
+ return ( !Q_stricmp( pGame, "cstrike" ) );
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PC Implementation
+//////////////////////////////////////////////////////////////////////////
+
+
+
+int AchivementSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight )
+{
+ if ( (*pLeft)->IsAchieved() && !(*pRight)->IsAchieved() )
+ return -1;
+
+ if ( !(*pLeft)->IsAchieved() && (*pRight)->IsAchieved() )
+ return 1;
+
+ if ( (*pLeft)->GetAchievementID() < (*pRight)->GetAchievementID() )
+ return -1;
+
+ if ( (*pLeft)->GetAchievementID() > (*pRight)->GetAchievementID() )
+ return 1;
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CAchievementsPage::CAchievementsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog")
+{
+ m_iFixedWidth = 900; // Give this an initial value in order to set a proper size
+ SetBounds(0, 0, 900, 780);
+ SetMinimumSize( 256, 780 );
+
+ m_pStatCard = new StatCard(this, "ignored");
+
+ m_pAchievementsList = new vgui::PanelListPanel( this, "listpanel_achievements" );
+ m_pAchievementsList->SetFirstColumnWidth( 0 );
+
+ m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" );
+ m_pGroupsList->SetFirstColumnWidth( 0 );
+
+ m_pListBG = new vgui::ImagePanel( this, "listpanel_background" );
+
+ m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) );
+ m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
+
+ ListenForGameEvent( "player_stats_updated" );
+ ListenForGameEvent( "achievement_earned_local" );
+
+ // int that holds the highest number achievement id we've found
+ int iHighestAchievementIDSeen = -1;
+ int iNextGroupBoundary = 1000;
+
+ Q_memset( m_AchievementGroups, 0, sizeof(m_AchievementGroups) );
+ m_iNumAchievementGroups = 0;
+
+ // Base groups
+ int iCount = g_AchievementMgrCS.GetAchievementCount();
+ for ( int i = 0; i < iCount; ++i )
+ {
+ CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
+
+ if ( !pAchievement )
+ continue;
+
+ int iAchievementID = pAchievement->GetAchievementID();
+
+ if ( iAchievementID > iHighestAchievementIDSeen )
+ {
+ // if it's crossed the next group boundary, create a new group
+ if ( iAchievementID >= iNextGroupBoundary )
+ {
+ int iNewGroupBoundary = iAchievementID;
+ CreateNewAchievementGroup( iNewGroupBoundary, iNewGroupBoundary+99 );
+
+ iNextGroupBoundary = iNewGroupBoundary + 100;
+ }
+
+ iHighestAchievementIDSeen = iAchievementID;
+ }
+ }
+
+ LoadControlSettings("resource/ui/CSAchievementsDialog.res");
+ UpdateTotalProgressDisplay();
+ CreateOrUpdateComboItems( true );
+
+ // Default display shows the first achievement group
+ UpdateAchievementList(1001, 1100);
+
+ m_bStatsDirty = true;
+ m_bAchievementsDirty = true;
+}
+
+CAchievementsPage::~CAchievementsPage()
+{
+ g_AchievementMgrCS.SaveGlobalStateIfDirty( false ); // check for saving here to store achievements we want pinned to HUD
+
+ m_pAchievementsList->DeleteAllItems();
+ delete m_pAchievementsList;
+ delete m_pPercentageBarBackground;
+ delete m_pPercentageBar;
+}
+
+void CAchievementsPage::CreateNewAchievementGroup( int iMinRange, int iMaxRange )
+{
+ m_AchievementGroups[m_iNumAchievementGroups].m_iMinRange = iMinRange;
+ m_AchievementGroups[m_iNumAchievementGroups].m_iMaxRange = iMaxRange;
+ m_iNumAchievementGroups++;
+}
+
+//----------------------------------------------------------
+// Get the width we're going to lock at
+//----------------------------------------------------------
+void CAchievementsPage::ApplySettings( KeyValues *pResourceData )
+{
+ m_iFixedWidth = pResourceData->GetInt( "wide", 512 );
+
+ BaseClass::ApplySettings( pResourceData );
+}
+
+//----------------------------------------------------------
+// Preserve our width to the one in the .res file
+//----------------------------------------------------------
+void CAchievementsPage::OnSizeChanged(int newWide, int newTall)
+{
+ // Lock the width, but allow height scaling
+ if ( newWide != m_iFixedWidth )
+ {
+ SetSize( m_iFixedWidth, newTall );
+ return;
+ }
+
+ BaseClass::OnSizeChanged(newWide, newTall);
+}
+
+//----------------------------------------------------------
+// Re-populate the achievement list with the selected group
+//----------------------------------------------------------
+void CAchievementsPage::UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel)
+{
+ if (!groupPanel)
+ return;
+
+ UpdateAchievementList( groupPanel->GetFirstAchievementID(), groupPanel->GetLastAchievementID() );
+
+ vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() );
+
+ // Update active status for button display
+ for (int i = 0; i < m_pGroupsList->GetItemCount(); i++)
+ {
+ CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ if ( pPanel != groupPanel )
+ {
+ pPanel->SetGroupActive( false );
+ }
+ else
+ {
+ pPanel->SetGroupActive( true );
+ }
+
+ pPanel->UpdateAchievementInfo( pGroupScheme );
+ }
+ }
+}
+
+void CAchievementsPage::UpdateTotalProgressDisplay()
+{
+ // Set up total completion percentage bar
+ float flCompletion = 0.0f;
+
+ int iCount = g_AchievementMgrCS.GetAchievementCount();
+ int nUnlocked = 0;
+
+ if ( iCount > 0 )
+ {
+ for ( int i = 0; i < iCount; ++i )
+ {
+ CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
+
+ if ( pAchievement && pAchievement->IsAchieved() )
+ ++nUnlocked;
+ }
+
+ flCompletion = (((float)nUnlocked) / ((float)g_AchievementMgrCS.GetAchievementCount()));
+ }
+
+ char szPercentageText[64];
+ V_sprintf_safe( szPercentageText, "%d / %d",
+ nUnlocked, g_AchievementMgrCS.GetAchievementCount() );
+
+ SetControlString( "PercentageText", szPercentageText );
+ SetControlVisible( "PercentageText", true );
+ SetControlVisible( "CompletionText", true );
+
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ Color clrHighlight = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+ Color clrWhite(255, 255, 255, 255);
+
+ Color cProgressBar = Color( static_cast<float>( clrHighlight.r() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.r() ) * flCompletion,
+ static_cast<float>( clrHighlight.g() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.g() ) * flCompletion,
+ static_cast<float>( clrHighlight.b() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.b() ) * flCompletion,
+ static_cast<float>( clrHighlight.a() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.a() ) * flCompletion );
+
+ m_pPercentageBar->SetFgColor( cProgressBar );
+ m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion );
+
+ SetControlVisible( "PercentageBarBackground", true );
+ SetControlVisible( "PercentageBar", true );
+}
+
+//----------------------------------------------------------
+// Re-populate the achievement list with the selected group
+//----------------------------------------------------------
+void CAchievementsPage::UpdateAchievementList(int minID, int maxID)
+{
+ int iMinRange = minID;
+ int iMaxRange = maxID;
+
+ int iCount = g_AchievementMgrCS.GetAchievementCount();
+
+ CUtlVector<CCSBaseAchievement*> sortedAchivementList;
+ sortedAchivementList.EnsureCapacity(iCount);
+
+ for ( int i = 0; i < iCount; ++i )
+ {
+ CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex(i));
+
+ if ( !pAchievement )
+ continue;
+
+ int iAchievementID = pAchievement->GetAchievementID();
+
+ if ( iAchievementID < iMinRange || iAchievementID > iMaxRange )
+ continue;
+
+ // don't show hidden achievements if not achieved
+ if ( pAchievement->ShouldHideUntilAchieved() && !pAchievement->IsAchieved() )
+ continue;
+
+ sortedAchivementList.AddToTail(pAchievement);
+ }
+
+ sortedAchivementList.Sort(AchivementSortPredicate);
+
+ m_pAchievementsList->DeleteAllItems();
+
+ FOR_EACH_VEC(sortedAchivementList, i)
+ {
+ CCSBaseAchievement* pAchievement = sortedAchivementList[i];
+
+ CAchievementsPageItemPanel *pAchievementItemPanel = new CAchievementsPageItemPanel( m_pAchievementsList, "AchievementDialogItemPanel");
+ pAchievementItemPanel->SetAchievementInfo(pAchievement);
+
+ // force all our new panel to have the correct internal layout and size so that our parent container can layout properly
+ pAchievementItemPanel->InvalidateLayout(true, true);
+
+ m_pAchievementsList->AddItem( NULL, pAchievementItemPanel );
+ }
+
+ m_pAchievementsList->MoveScrollBarToTop();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from achievementsdialog.res in hl2/resource/ui/
+// Sets up progress bar displaying total achievement unlocking progress by the user.
+//-----------------------------------------------------------------------------
+void CAchievementsPage::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pGroupsList->SetBgColor(Color(86,86,86,255));
+
+ SetBgColor(Color(86,86,86,255));
+
+ // Set text color for percentage
+ Panel *pPanel;
+ pPanel = FindChildByName("PercentageText");
+ if (pPanel)
+ {
+ pPanel->SetFgColor(Color(157, 194, 80, 255));
+ }
+
+ // Set text color for achievement earned label
+ pPanel = FindChildByName("AchievementsEarnedLabel");
+ if (pPanel)
+ {
+ pPanel->SetFgColor(Color(157, 194, 80, 255));
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Each sub-panel gets its data updated
+//-----------------------------------------------------------------------------
+void CAchievementsPage::UpdateAchievementDialogInfo( void )
+{
+ // Hide the group list scrollbar
+ if (m_pGroupsList->GetScrollbar())
+ {
+ m_pGroupsList->GetScrollbar()->SetWide(0);
+ }
+
+ int iCount = m_pAchievementsList->GetItemCount();
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ int i;
+ for ( i = 0; i < iCount; i++ )
+ {
+ CAchievementsPageItemPanel *pPanel = (CAchievementsPageItemPanel*)m_pAchievementsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ pPanel->UpdateAchievementInfo( pScheme );
+ }
+ }
+
+ // Update all group panels
+ int iGroupCount = m_pGroupsList->GetItemCount();
+ for ( i = 0; i < iGroupCount; i++ )
+ {
+ CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ pPanel->UpdateAchievementInfo( pScheme );
+
+ if ( pPanel->IsGroupActive() )
+ {
+ UpdateAchievementList( pPanel );
+ }
+ }
+ }
+
+ // update the groups and overall progress bar
+ CreateOrUpdateComboItems( false ); // update them with new achieved counts
+
+ UpdateTotalProgressDisplay();
+
+ m_pStatCard->UpdateInfo();
+
+ m_bAchievementsDirty = false;
+ m_bStatsDirty = false;
+}
+
+void CAchievementsPage::CreateOrUpdateComboItems( bool bCreate )
+{
+ // Build up achievement group names
+ for ( int i=0;i<m_iNumAchievementGroups;i++ )
+ {
+ char buf[128];
+
+ int achievementRangeStart = (m_AchievementGroups[i].m_iMinRange / 1000) * 1000;
+ Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart );
+
+ wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf );
+
+ if ( !wzGroupName )
+ {
+ wzGroupName = L"Need Title ( %s1 of %s2 )";
+ }
+
+ wchar_t wzGroupTitle[128];
+
+ if ( wzGroupName )
+ {
+ // Determine number of achievements in the group which have been awarded
+ int numAwarded = 0;
+ int numTested = 0;
+ for (int j = m_AchievementGroups[i].m_iMinRange; j < m_AchievementGroups[i].m_iMaxRange; j++)
+ {
+ IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( j );
+
+ if ( !pCur )
+ continue;
+
+ numTested++;
+
+ if ( pCur->IsAchieved() )
+ {
+ numAwarded++;
+ }
+ }
+
+ wchar_t wzNumUnlocked[8];
+ V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded );
+
+ wchar_t wzNumAchievements[8];
+ V_snwprintf( wzNumAchievements, ARRAYSIZE( wzNumAchievements ), L"%d", numTested );
+
+ g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 0 );
+ }
+
+ KeyValues *pKV = new KeyValues( "grp" );
+ pKV->SetInt( "minrange", m_AchievementGroups[i].m_iMinRange );
+ pKV->SetInt( "maxrange", m_AchievementGroups[i].m_iMaxRange );
+
+ if ( bCreate )
+ {
+ // Create an achievement group instance
+ CAchievementsPageGroupPanel *achievementGroupPanel = new CAchievementsPageGroupPanel( m_pGroupsList, this, "AchievementDialogGroupPanel", i );
+ achievementGroupPanel->SetGroupInfo( wzGroupTitle, m_AchievementGroups[i].m_iMinRange, m_AchievementGroups[i].m_iMaxRange );
+
+ if (i == 0)
+ {
+ achievementGroupPanel->SetGroupActive(true);
+ }
+ else
+ {
+ achievementGroupPanel->SetGroupActive(false);
+ }
+
+ m_pGroupsList->AddItem( NULL, achievementGroupPanel );
+ }
+ }
+
+ m_pStatCard->UpdateInfo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CAchievementsPageItemPanel::CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name) : BaseClass( parent, name )
+{
+ m_pParent = parent;
+ m_pSchemeSettings = NULL;
+
+ m_pAchievementIcon = SETUP_PANEL(new vgui::ImagePanel( this, "AchievementIcon" ));
+ m_pAchievementNameLabel = new vgui::Label( this, "AchievementName", "name" );
+ m_pAchievementDescLabel = new vgui::Label( this, "AchievementDesc", "desc" );
+ m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
+ m_pPercentageText = new vgui::Label( this, "PercentageText", "" );
+ m_pAwardDate = new vgui::Label( this, "AwardDate", "date" );
+ m_pShowOnHUDButton = new vgui::CheckButton( this, "ShowOnHudToggle", "" );
+ m_pShowOnHUDButton->SetMouseInputEnabled( true );
+ m_pShowOnHUDButton->SetEnabled( true );
+ m_pShowOnHUDButton->SetCheckButtonCheckable( true );
+ m_pShowOnHUDButton->AddActionSignalTarget( this );
+
+ m_pHiddenHUDToggleButton = new CHiddenHUDToggleButton( this, "HiddenHUDToggle", "" );
+ m_pHiddenHUDToggleButton->SetPaintBorderEnabled( false );
+
+
+ SetMouseInputEnabled( true );
+ parent->SetMouseInputEnabled( true );
+}
+
+CAchievementsPageItemPanel::~CAchievementsPageItemPanel()
+{
+ delete m_pAchievementIcon;
+ delete m_pAchievementNameLabel;
+ delete m_pAchievementDescLabel;
+ delete m_pPercentageBar;
+ delete m_pPercentageText;
+ delete m_pAwardDate;
+ delete m_pShowOnHUDButton;
+ delete m_pHiddenHUDToggleButton;
+}
+
+void CAchievementsPageItemPanel::ToggleShowOnHUDButton()
+{
+ if (m_pShowOnHUDButton)
+ {
+ m_pShowOnHUDButton->SetSelected( !m_pShowOnHUDButton->IsSelected() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates displayed achievement data. In applyschemesettings, and when gameui activates.
+//-----------------------------------------------------------------------------
+void CAchievementsPageItemPanel::UpdateAchievementInfo( vgui::IScheme* pScheme )
+{
+ if ( m_pSourceAchievement && m_pSchemeSettings )
+ {
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Get achievement name and description text from the localized file
+ //=============================================================================
+
+ // Set name, description and unlocked state text
+ m_pAchievementNameLabel->SetText( ACHIEVEMENT_LOCALIZED_NAME( m_pSourceAchievement ) );
+ m_pAchievementDescLabel->SetText( ACHIEVEMENT_LOCALIZED_DESC( m_pSourceAchievement ) );
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ // Setup icon
+ // get the vtfFilename from the path.
+
+ // Display percentage completion for progressive achievements
+ // Set up total completion percentage bar. Goal > 1 means its a progress achievement.
+ CSUpdateProgressBarForPage( this, m_pSourceAchievement, m_clrProgressBar );
+
+ if ( m_pSourceAchievement->IsAchieved() )
+ {
+ CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement );
+
+ SetBgColor( pScheme->GetColor( "AchievementsLightGrey", Color(255, 0, 0, 255) ) );
+
+ m_pAchievementNameLabel->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) );
+
+ Color fgColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) );
+ m_pAchievementDescLabel->SetFgColor( fgColor );
+ m_pPercentageText->SetFgColor( fgColor );
+ m_pShowOnHUDButton->SetVisible( false );
+ m_pShowOnHUDButton->SetSelected( false );
+ m_pHiddenHUDToggleButton->SetVisible( false );
+ m_pAwardDate->SetVisible( true );
+ m_pAwardDate->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) );
+
+ // Assign the award date text
+ int year, month, day, hour, minute, second;
+ if ( m_pSourceAchievement->GetAwardTime(year, month, day, hour, minute, second) )
+ {
+ char dateBuffer[32] = "";
+ Q_snprintf( dateBuffer, 32, "%4d-%02d-%02d", year, month, day );
+ m_pAwardDate->SetText( dateBuffer );
+ }
+ else
+ m_pAwardDate->SetText( "" );
+ }
+ else
+ {
+ CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement, "_bw" );
+
+ SetBgColor( pScheme->GetColor( "AchievementsDarkGrey", Color(255, 0, 0, 255) ) );
+
+ Color fgColor = pScheme->GetColor( "AchievementsInactiveFG", Color(255, 255, 255, 255) );
+ m_pAchievementNameLabel->SetFgColor( fgColor );
+ m_pAchievementDescLabel->SetFgColor( fgColor );
+ m_pPercentageText->SetFgColor( fgColor );
+
+ if ( CSGameSupportsAchievementTrackerForPage() )
+ {
+ m_pShowOnHUDButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() );
+ m_pShowOnHUDButton->SetSelected( m_pSourceAchievement->ShouldShowOnHUD() );
+
+ m_pHiddenHUDToggleButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() );
+ }
+ else
+ {
+ m_pShowOnHUDButton->SetVisible( false );
+ m_pHiddenHUDToggleButton->SetVisible( false );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes a local copy of a pointer to the achievement entity stored on the client.
+//-----------------------------------------------------------------------------
+void CAchievementsPageItemPanel::SetAchievementInfo( CCSBaseAchievement* pAchievement )
+{
+ if ( !pAchievement )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ m_pSourceAchievement = pAchievement;
+ m_iSourceAchievementIndex = pAchievement->GetAchievementID();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementsPageItemPanel::PreloadResourceFile( void )
+{
+ const char *controlResourceName = "resource/ui/AchievementItem.res";
+
+ g_pPreloadedCSAchievementPageItemLayout = new KeyValues(controlResourceName);
+ g_pPreloadedCSAchievementPageItemLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
+
+/*
+ // precache all achievement icons
+ int iCount = g_AchievementMgrCS.GetAchievementCount();
+ for ( int i = 0; i < iCount; ++i )
+ {
+ CCSBaseAchievement* pAchievement = dynamic_cast<CCSBaseAchievement*>(g_AchievementMgrCS.GetAchievementByIndex( i ));
+ char imagePath[_MAX_PATH];
+
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
+ Q_strncat( imagePath, "_bw", sizeof(imagePath), COPY_ALL_CHARACTERS );
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ scheme()->GetImage(imagePath, true);
+
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ scheme()->GetImage(imagePath, true);
+ }
+*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from hl2/resource/ui/achievementitem.res
+// Sets display info for this achievement item.
+//-----------------------------------------------------------------------------
+void CAchievementsPageItemPanel::ApplySchemeSettings( vgui::IScheme* pScheme )
+{
+ if ( !g_pPreloadedCSAchievementPageItemLayout )
+ {
+ PreloadResourceFile();
+ }
+
+ LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageItemLayout );
+
+ m_pSchemeSettings = pScheme;
+
+ if ( !m_pSourceAchievement )
+ {
+ return;
+ }
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // m_pSchemeSettings must be set for this.
+ UpdateAchievementInfo( pScheme );
+}
+
+void CAchievementsPageItemPanel::OnCheckButtonChecked(Panel *panel)
+{
+ if ( CSGameSupportsAchievementTrackerForPage() && panel == m_pShowOnHUDButton && m_pSourceAchievement )
+ {
+ m_pSourceAchievement->SetShowOnHUD( m_pShowOnHUDButton->IsSelected() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CAchievementsPageGroupPanel::CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name )
+{
+ m_pParent = parent;
+ m_pOwner = owner;
+ m_pSchemeSettings = NULL;
+
+ m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" ));
+ m_pAchievementGroupLabel = new vgui::Label( this, "GroupName", "name" );
+ m_pPercentageText = new vgui::Label( this, "GroupPercentageText", "1/1" );
+ m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "GroupPercentageBar" ) );
+ m_pGroupButton = new CGroupButton( this, "GroupButton", "" );
+ m_pGroupButton->SetPos( 0, 0 );
+ m_pGroupButton->SetZPos( 20 );
+ m_pGroupButton->SetWide( 256 );
+ m_pGroupButton->SetTall( 64 );
+ SetMouseInputEnabled( true );
+ parent->SetMouseInputEnabled( true );
+
+ m_bActiveButton = false;
+}
+
+CAchievementsPageGroupPanel::~CAchievementsPageGroupPanel()
+{
+ delete m_pAchievementGroupLabel;
+ delete m_pPercentageBar;
+ delete m_pPercentageText;
+ delete m_pGroupIcon;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from hl2/resource/ui/achievementitem.res
+// Sets display info for this achievement item.
+//-----------------------------------------------------------------------------
+void CAchievementsPageGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme )
+{
+ if ( !g_pPreloadedCSAchievementPageGroupLayout )
+ {
+ PreloadResourceFile();
+ }
+
+ LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageGroupLayout );
+
+ m_pSchemeSettings = pScheme;
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // m_pSchemeSettings must be set for this.
+ UpdateAchievementInfo( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates displayed achievement data. In ApplySchemeSettings(), and
+// when gameui activates.
+//-----------------------------------------------------------------------------
+void CAchievementsPageGroupPanel::UpdateAchievementInfo( vgui::IScheme* pScheme )
+{
+ if ( m_pSchemeSettings )
+ {
+ int numAwarded = 0;
+ int numTested = 0;
+
+ char buf[128];
+ int achievementRangeStart = (m_iFirstAchievementID / 1000) * 1000;
+ Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart );
+
+ wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf );
+
+ if ( !wzGroupName )
+ {
+ wzGroupName = L"Need Title ( %s1 of %s2 )";
+ }
+
+ wchar_t wzGroupTitle[128];
+
+ if ( wzGroupName )
+ {
+ // Determine number of achievements in the group which have been awarded
+ for (int i = m_iFirstAchievementID; i < m_iLastAchievementID; i++)
+ {
+ IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( i );
+
+ if ( !pCur )
+ continue;
+
+ numTested++;
+
+ if ( pCur->IsAchieved() )
+ {
+ numAwarded++;
+ }
+ }
+
+ wchar_t wzNumUnlocked[8];
+ V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded );
+
+ wchar_t wzNumAchievements[8];
+ V_snwprintf( wzNumAchievements,ARRAYSIZE( wzNumAchievements ), L"%d", numTested );
+
+ g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 2, wzNumUnlocked, wzNumAchievements );
+ }
+
+ // Set group name text
+ m_pAchievementGroupLabel->SetText( wzGroupTitle );//m_pGroupName );
+ m_pAchievementGroupLabel->SetFgColor(Color(157, 194, 80, 255));
+
+ char* buff[32];
+ Q_snprintf( (char*)buff, 32, "%d / %d", numAwarded, numTested );
+ m_pPercentageText->SetText( (const char*)buff );
+ m_pPercentageText->SetFgColor(Color(157, 194, 80, 255));
+
+ if ( !m_bActiveButton )
+ {
+ CSLoadIconForPage( m_pGroupIcon, "achievement-btn-up" );
+ }
+ else
+ {
+ CSLoadIconForPage( m_pGroupIcon, "achievement-btn-select" );
+ }
+
+ // Update the percentage complete bar
+ vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBar" );
+ vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBarBackground" );
+
+ if ( pPercentageBar && pPercentageBarBkg )
+ {
+ float flCompletion = (float)numAwarded / (float)numTested;
+ pPercentageBar->SetFillColor( Color(157, 194, 80, 255) );
+ pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion );
+
+ SetControlVisible( "GroupPercentageBarBackground", true );
+ SetControlVisible( "GroupPercentageBar", true );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementsPageGroupPanel::PreloadResourceFile( void )
+{
+ const char *controlResourceName = "resource/ui/AchievementGroup.res";
+
+ g_pPreloadedCSAchievementPageGroupLayout = new KeyValues(controlResourceName);
+ g_pPreloadedCSAchievementPageGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Assigns a name and achievement id bounds for an achievement group.
+//-----------------------------------------------------------------------------
+void CAchievementsPageGroupPanel::SetGroupInfo( const wchar_t* name, int firstAchievementID, int lastAchievementID )
+{
+ // Store away the group name
+ short _textLen = (short)wcslen(name) + 1;
+ m_pGroupName = new wchar_t[_textLen];
+ Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) );
+
+ // Store off the start & end achievement IDs
+ m_iFirstAchievementID = firstAchievementID;
+ m_iLastAchievementID = lastAchievementID;
+}
+
+CGroupButton::CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
+BaseClass( pParent, pName, pText )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the case where the user presses an achievement group button.
+//-----------------------------------------------------------------------------
+void CGroupButton::DoClick( void )
+{
+ // Process when a group button is hit
+ CAchievementsPageGroupPanel* pParent = static_cast<CAchievementsPageGroupPanel*>(GetParent());
+
+ if (pParent)
+ {
+ CAchievementsPage* pAchievementsPage = static_cast<CAchievementsPage*>(pParent->GetOwner());
+
+ if (pAchievementsPage)
+ {
+ // Update the list of group achievements
+ pAchievementsPage->UpdateAchievementList( pParent );
+ }
+ }
+}
+
+void CAchievementsPage::OnPageShow()
+{
+ m_pGroupsList->GetScrollbar()->SetWide(0);
+}
+
+void CAchievementsPage::FireGameEvent( IGameEvent *event )
+{
+ const char *type = event->GetName();
+
+ if ( 0 == Q_strcmp( type, "achievement_earned_local" ) )
+ m_bAchievementsDirty = true;
+
+ if ( 0 == Q_strcmp( type, "player_stats_updated" ) )
+ m_bStatsDirty = true;
+}
+
+void CAchievementsPage::OnThink()
+{
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ if ( m_bAchievementsDirty )
+ {
+ UpdateAchievementDialogInfo();
+ }
+ else if ( m_bStatsDirty )
+ {
+ // Update progress for currently displayed achievements
+ int itemId = m_pAchievementsList->FirstItem();
+
+ while (itemId != m_pAchievementsList->InvalidItemID() )
+ {
+ CAchievementsPageItemPanel *pAchievementItem = dynamic_cast<CAchievementsPageItemPanel*>(m_pAchievementsList->GetItemPanel(itemId));
+ pAchievementItem->UpdateAchievementInfo(pScheme);
+
+ itemId = m_pAchievementsList->NextItem(itemId);
+ }
+ m_bStatsDirty = false;
+ }
+}
+
+CHiddenHUDToggleButton::CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
+BaseClass( pParent, pName, pText )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the case where the user shift-clicks on an un-awarded achievement.
+//-----------------------------------------------------------------------------
+void CHiddenHUDToggleButton::DoClick( void )
+{
+ if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) )
+ {
+ // Process when a group button is hit
+ CAchievementsPageItemPanel* pParent = static_cast<CAchievementsPageItemPanel*>(GetParent());
+
+ if (pParent)
+ {
+ pParent->ToggleShowOnHUDButton();
+ }
+ }
+}
diff --git a/game/client/cstrike/VGUI/achievements_page.h b/game/client/cstrike/VGUI/achievements_page.h
new file mode 100644
index 0000000..2066b1d
--- /dev/null
+++ b/game/client/cstrike/VGUI/achievements_page.h
@@ -0,0 +1,218 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSACHIEVEMENTSPAGE_H
+#define CSACHIEVEMENTSPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/PropertyPage.h"
+#include "vgui_controls/Button.h"
+#include "c_cs_player.h"
+#include "vgui_avatarimage.h"
+#include "GameEventListener.h"
+
+class CCSBaseAchievement;
+class IScheme;
+class CAchievementsPageGroupPanel;
+class StatCard;
+
+#define ACHIEVED_ICON_PATH "hud/icon_check.vtf"
+#define LOCK_ICON_PATH "hud/icon_locked.vtf"
+
+// Loads an achievement's icon into a specified image panel, or turns the panel off if no achievement icon was found.
+bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement *pAchievement, const char *pszExt = NULL );
+
+// Loads an achievement's icon into a specified image panel, or turns the panel off if no achievement icon was found.
+bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt = NULL );
+
+// Updates a listed achievement item's progress bar.
+void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement *pAchievement, Color clrProgressBar );
+
+////////////////////////////////////////////////////////////////////////////
+// PC version
+//////////////////////////////////////////////////////////////////////////
+class CAchievementsPage : public vgui::PropertyPage, public CGameEventListener
+{
+ DECLARE_CLASS_SIMPLE ( CAchievementsPage, vgui::PropertyPage );
+
+public:
+ CAchievementsPage( vgui::Panel *parent, const char *name );
+ ~CAchievementsPage();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ void UpdateTotalProgressDisplay();
+ virtual void UpdateAchievementDialogInfo( void );
+
+ virtual void OnPageShow();
+ virtual void OnThink();
+
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void OnSizeChanged( int newWide, int newTall );
+
+ virtual void FireGameEvent( IGameEvent *event );
+
+ void CreateNewAchievementGroup( int iMinRange, int iMaxRange );
+ void CreateOrUpdateComboItems( bool bCreate );
+ void UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel);
+ void UpdateAchievementList(int minID, int maxID);
+
+ vgui::PanelListPanel *m_pAchievementsList;
+ vgui::ImagePanel *m_pListBG;
+
+ vgui::PanelListPanel *m_pGroupsList;
+ vgui::ImagePanel *m_pGroupListBG;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+
+ StatCard* m_pStatCard;
+
+ int m_iFixedWidth;
+
+ bool m_bStatsDirty;
+ bool m_bAchievementsDirty;
+
+ typedef struct
+ {
+ int m_iMinRange;
+ int m_iMaxRange;
+ } achievement_group_t;
+
+ int m_iNumAchievementGroups;
+
+ achievement_group_t m_AchievementGroups[15];
+};
+
+class CHiddenHUDToggleButton : public vgui::Button
+{
+ DECLARE_CLASS_SIMPLE( CHiddenHUDToggleButton, vgui::Button );
+
+public:
+
+ CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText );
+
+ virtual void DoClick( void );
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Individual item panel, displaying stats for one achievement
+class CAchievementsPageItemPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CAchievementsPageItemPanel, vgui::EditablePanel );
+
+public:
+ CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name);
+ ~CAchievementsPageItemPanel();
+
+ void SetAchievementInfo ( CCSBaseAchievement* pAchievement );
+ CCSBaseAchievement* GetAchievementInfo( void ) { return m_pSourceAchievement; }
+ void UpdateAchievementInfo( vgui::IScheme *pScheme );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ void ToggleShowOnHUDButton();
+
+ MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel );
+
+private:
+ static void PreloadResourceFile();
+
+ CCSBaseAchievement* m_pSourceAchievement;
+ int m_iSourceAchievementIndex;
+
+ vgui::PanelListPanel *m_pParent;
+
+ vgui::Label *m_pAchievementNameLabel;
+ vgui::Label *m_pAchievementDescLabel;
+ vgui::Label *m_pPercentageText;
+ vgui::Label *m_pAwardDate;
+
+ vgui::ImagePanel *m_pLockedIcon;
+ vgui::ImagePanel *m_pAchievementIcon;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+
+ vgui::CheckButton *m_pShowOnHUDButton;
+
+ vgui::IScheme *m_pSchemeSettings;
+
+ CHiddenHUDToggleButton *m_pHiddenHUDToggleButton;
+
+ CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" );
+};
+
+class CGroupButton : public vgui::Button
+{
+ DECLARE_CLASS_SIMPLE( CGroupButton, vgui::Button );
+
+public:
+
+ CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText );
+
+ virtual void DoClick( void );
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Individual achievement group panel, displaying info for one achievement group
+class CAchievementsPageGroupPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CAchievementsPageGroupPanel, vgui::EditablePanel );
+
+public:
+ CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID );
+ ~CAchievementsPageGroupPanel();
+
+ void SetGroupInfo ( const wchar_t* name, int firstAchievementID, int lastAchievementID );
+ void UpdateAchievementInfo( vgui::IScheme *pScheme );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ int GetFirstAchievementID() { return m_iFirstAchievementID; }
+ int GetLastAchievementID() { return m_iLastAchievementID; }
+
+ vgui::PanelListPanel* GetParent() { return m_pParent; }
+ CAchievementsPage* GetOwner() { return m_pOwner; }
+
+ void SetGroupActive(bool active) { m_bActiveButton = active; }
+ bool IsGroupActive() { return m_bActiveButton; }
+
+private:
+ void PreloadResourceFile( void );
+
+ vgui::PanelListPanel *m_pParent;
+ CAchievementsPage *m_pOwner;
+
+ vgui::Label *m_pAchievementGroupLabel;
+ vgui::Label *m_pPercentageText;
+
+ CGroupButton *m_pGroupButton;
+
+ vgui::ImagePanel *m_pGroupIcon;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+
+ vgui::IScheme *m_pSchemeSettings;
+
+ bool m_bActiveButton;
+
+ CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" );
+
+ int m_iFirstAchievementID;
+ int m_iLastAchievementID;
+
+ wchar_t *m_pGroupName;
+};
+
+
+
+#endif // CSACHIEVEMENTSPAGE_H
diff --git a/game/client/cstrike/VGUI/backgroundpanel.cpp b/game/client/cstrike/VGUI/backgroundpanel.cpp
new file mode 100644
index 0000000..c875217
--- /dev/null
+++ b/game/client/cstrike/VGUI/backgroundpanel.cpp
@@ -0,0 +1,676 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "backgroundpanel.h"
+
+#include <vgui/IVGui.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/Label.h>
+#include <vgui/ILocalize.h>
+#include "vgui_controls/BuildGroup.h"
+#include "vgui_controls/BitmapImagePanel.h"
+
+using namespace vgui;
+
+#define DEBUG_WINDOW_RESIZING 0
+#define DEBUG_WINDOW_REPOSITIONING 0
+
+//-----------------------------------------------------------------------------
+const int NumSegments = 7;
+static int coord[NumSegments+1] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 6,
+ 9,
+ 10
+};
+
+//-----------------------------------------------------------------------------
+void DrawRoundedBackground( Color bgColor, int wide, int tall )
+{
+ int x1, x2, y1, y2;
+ surface()->DrawSetColor(bgColor);
+ surface()->DrawSetTextColor(bgColor);
+
+ int i;
+
+ // top-left corner --------------------------------------------------------
+ int xDir = 1;
+ int yDir = -1;
+ int xIndex = 0;
+ int yIndex = NumSegments - 1;
+ int xMult = 1;
+ int yMult = 1;
+ int x = 0;
+ int y = 0;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = y + coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // top-right corner -------------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = wide;
+ y = 0;
+ xMult = -1;
+ yMult = 1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = y + coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // bottom-right corner ----------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = wide;
+ y = tall;
+ xMult = -1;
+ yMult = -1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = y - coord[NumSegments];
+ y2 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // bottom-left corner -----------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = 0;
+ y = tall;
+ xMult = 1;
+ yMult = -1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = y - coord[NumSegments];
+ y2 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // paint between top left and bottom left ---------------------------------
+ x1 = 0;
+ x2 = coord[NumSegments];
+ y1 = coord[NumSegments];
+ y2 = tall - coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ // paint between left and right -------------------------------------------
+ x1 = coord[NumSegments];
+ x2 = wide - coord[NumSegments];
+ y1 = 0;
+ y2 = tall;
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ // paint between top right and bottom right -------------------------------
+ x1 = wide - coord[NumSegments];
+ x2 = wide;
+ y1 = coord[NumSegments];
+ y2 = tall - coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+}
+
+//-----------------------------------------------------------------------------
+void DrawRoundedBorder( Color borderColor, int wide, int tall )
+{
+ int x1, x2, y1, y2;
+ surface()->DrawSetColor(borderColor);
+ surface()->DrawSetTextColor(borderColor);
+
+ int i;
+
+ // top-left corner --------------------------------------------------------
+ int xDir = 1;
+ int yDir = -1;
+ int xIndex = 0;
+ int yIndex = NumSegments - 1;
+ int xMult = 1;
+ int yMult = 1;
+ int x = 0;
+ int y = 0;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // top-right corner -------------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = wide;
+ y = 0;
+ xMult = -1;
+ yMult = 1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // bottom-right corner ----------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = wide;
+ y = tall;
+ xMult = -1;
+ yMult = -1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // bottom-left corner -----------------------------------------------------
+ xDir = 1;
+ yDir = -1;
+ xIndex = 0;
+ yIndex = NumSegments - 1;
+ x = 0;
+ y = tall;
+ xMult = 1;
+ yMult = -1;
+ for ( i=0; i<NumSegments; ++i )
+ {
+ x1 = MIN( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ x2 = MAX( x + coord[xIndex]*xMult, x + coord[xIndex+1]*xMult );
+ y1 = MIN( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ y2 = MAX( y + coord[yIndex]*yMult, y + coord[yIndex+1]*yMult );
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+ xIndex += xDir;
+ yIndex += yDir;
+ }
+
+ // top --------------------------------------------------------------------
+ x1 = coord[NumSegments];
+ x2 = wide - coord[NumSegments];
+ y1 = 0;
+ y2 = 1;
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ // bottom -----------------------------------------------------------------
+ x1 = coord[NumSegments];
+ x2 = wide - coord[NumSegments];
+ y1 = tall - 1;
+ y2 = tall;
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ // left -------------------------------------------------------------------
+ x1 = 0;
+ x2 = 1;
+ y1 = coord[NumSegments];
+ y2 = tall - coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+
+ // right ------------------------------------------------------------------
+ x1 = wide - 1;
+ x2 = wide;
+ y1 = coord[NumSegments];
+ y2 = tall - coord[NumSegments];
+ surface()->DrawFilledRect( x1, y1, x2, y2 );
+}
+
+//-----------------------------------------------------------------------------
+class CaptionLabel : public Label
+{
+public:
+ CaptionLabel(Panel *parent, const char *panelName, const char *text) : Label(parent, panelName, text)
+ {
+ }
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ Label::ApplySchemeSettings( pScheme );
+ SetFont( pScheme->GetFont( "MenuTitle", IsProportional() ) );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: transform a normalized value into one that is scaled based the minimum
+// of the horizontal and vertical ratios
+//-----------------------------------------------------------------------------
+static int GetAlternateProportionalValueFromNormal(int normalizedValue)
+{
+ int wide, tall;
+ GetHudSize( wide, tall );
+ int proH, proW;
+ surface()->GetProportionalBase( proW, proH );
+ double scaleH = (double)tall / (double)proH;
+ double scaleW = (double)wide / (double)proW;
+ double scale = (scaleW < scaleH) ? scaleW : scaleH;
+
+ return (int)( normalizedValue * scale );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: transform a standard scaled value into one that is scaled based the minimum
+// of the horizontal and vertical ratios
+//-----------------------------------------------------------------------------
+int GetAlternateProportionalValueFromScaled( HScheme hScheme, int scaledValue)
+{
+ return GetAlternateProportionalValueFromNormal( scheme()->GetProportionalNormalizedValueEx( hScheme, scaledValue ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: moves and resizes a single control
+//-----------------------------------------------------------------------------
+static void RepositionControl( Panel *pPanel )
+{
+ int x, y, w, h;
+ pPanel->GetBounds(x, y, w, h);
+
+#if DEBUG_WINDOW_RESIZING
+ int x1, y1, w1, h1;
+ pPanel->GetBounds(x1, y1, w1, h1);
+ int x2, y2, w2, h2;
+ x2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), x1 );
+ y2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), y1 );
+ w2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), w1 );
+ h2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), h1 );
+#endif
+
+ x = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), x );
+ y = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), y );
+ w = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), w );
+ h = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), h );
+
+ pPanel->SetBounds(x, y, w, h);
+
+#if DEBUG_WINDOW_RESIZING
+ DevMsg( "Resizing '%s' from (%d,%d) %dx%d to (%d,%d) %dx%d -- initially was (%d,%d) %dx%d\n",
+ pPanel->GetName(), x1, y1, w1, h1, x, y, w, h, x2, y2, w2, h2 );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets colors etc for background image panels
+//-----------------------------------------------------------------------------
+void ApplyBackgroundSchemeSettings( EditablePanel *pWindow, vgui::IScheme *pScheme )
+{
+ Color bgColor = Color( 255, 255, 255, pScheme->GetColor( "BgColor", Color( 0, 0, 0, 0 ) )[3] );
+ Color fgColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) );
+
+ if ( !pWindow )
+ return;
+
+ CBitmapImagePanel *pBitmapPanel;
+
+ // corners --------------------------------------------
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopLeftPanel" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopRightPanel" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomLeftPanel" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomRightPanel" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+
+ // background -----------------------------------------
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopSolid" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "UpperMiddleSolid" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "LowerMiddleSolid" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomSolid" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( bgColor );
+ }
+
+ // Logo -----------------------------------------------
+ pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "ExclamationPanel" ));
+ if ( pBitmapPanel )
+ {
+ pBitmapPanel->setImageColor( fgColor );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Re-aligns background image panels so they are touching.
+//-----------------------------------------------------------------------------
+static void FixupBackgroundPanels( EditablePanel *pWindow, int offsetX, int offsetY )
+{
+ if ( !pWindow )
+ return;
+
+ int screenWide, screenTall;
+ pWindow->GetSize( screenWide, screenTall );
+
+ int inset = GetAlternateProportionalValueFromNormal( 20 );
+ int cornerSize = GetAlternateProportionalValueFromNormal( 10 );
+
+ int titleHeight = GetAlternateProportionalValueFromNormal( 42 );
+ int mainHeight = GetAlternateProportionalValueFromNormal( 376 );
+
+ int logoSize = titleHeight;
+
+ int captionInset = GetAlternateProportionalValueFromNormal( 76 );
+
+ Panel *pPanel;
+
+ // corners --------------------------------------------
+ pPanel = pWindow->FindChildByName( "TopLeftPanel" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset, offsetY + inset, cornerSize, cornerSize );
+ }
+
+ pPanel = pWindow->FindChildByName( "TopRightPanel" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, offsetY + inset, cornerSize, cornerSize );
+ }
+
+ pPanel = pWindow->FindChildByName( "BottomLeftPanel" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize );
+ }
+
+ pPanel = pWindow->FindChildByName( "BottomRightPanel" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize );
+ }
+
+ // background -----------------------------------------
+ pPanel = pWindow->FindChildByName( "TopSolid" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset + cornerSize, offsetY + inset, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize );
+ }
+
+ pPanel = pWindow->FindChildByName( "UpperMiddleSolid" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset, offsetY + inset + cornerSize, screenWide - 2*offsetX - 2*inset, titleHeight );
+ }
+
+ pPanel = pWindow->FindChildByName( "LowerMiddleSolid" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset + cornerSize, screenTall - offsetY - inset - cornerSize, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize );
+ }
+
+ pPanel = pWindow->FindChildByName( "BottomSolid" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize - mainHeight, screenWide - 2*offsetX - 2*inset, mainHeight );
+ }
+
+ // transparent border ---------------------------------
+ pPanel = pWindow->FindChildByName( "TopClear" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( 0, 0, screenWide, offsetY + inset );
+ }
+
+ pPanel = pWindow->FindChildByName( "BottomClear" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( 0, screenTall - offsetY - inset, screenWide, offsetY + inset );
+ }
+
+ pPanel = pWindow->FindChildByName( "LeftClear" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( 0, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset );
+ }
+
+ pPanel = pWindow->FindChildByName( "RightClear" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -20 );
+ pPanel->SetBounds( screenWide - offsetX - inset, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset );
+ }
+
+ // Logo -----------------------------------------------
+ int logoInset = (cornerSize + titleHeight - logoSize)/2;
+ pPanel = pWindow->FindChildByName( "ExclamationPanel" );
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -19 ); // higher than the background
+ pPanel->SetBounds( offsetX + inset + logoInset, offsetY + inset + logoInset, logoSize, logoSize );
+ }
+
+ // Title caption --------------------------------------
+ pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" ));
+ if ( pPanel )
+ {
+ pPanel->SetZPos( -19 ); // higher than the background
+ pPanel->SetBounds( offsetX + captionInset/*inset + 2*logoInset + logoSize*/, offsetY + inset + logoInset, screenWide, logoSize );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates background image panels
+//-----------------------------------------------------------------------------
+void CreateBackground( EditablePanel *pWindow )
+{
+ // corners --------------------------------------------
+ new CBitmapImagePanel( pWindow, "TopLeftPanel", "gfx/vgui/round_corner_nw" );
+ new CBitmapImagePanel( pWindow, "TopRightPanel", "gfx/vgui/round_corner_ne" );
+ new CBitmapImagePanel( pWindow, "BottomLeftPanel", "gfx/vgui/round_corner_sw" );
+ new CBitmapImagePanel( pWindow, "BottomRightPanel", "gfx/vgui/round_corner_se" );
+
+ // background -----------------------------------------
+ new CBitmapImagePanel( pWindow, "TopSolid", "gfx/vgui/solid_background" );
+ new CBitmapImagePanel( pWindow, "UpperMiddleSolid", "gfx/vgui/solid_background" );
+ new CBitmapImagePanel( pWindow, "LowerMiddleSolid", "gfx/vgui/solid_background" );
+ new CBitmapImagePanel( pWindow, "BottomSolid", "gfx/vgui/solid_background" );
+
+ // transparent border ---------------------------------
+ new CBitmapImagePanel( pWindow, "TopClear", "gfx/vgui/trans_background" );
+ new CBitmapImagePanel( pWindow, "BottomClear", "gfx/vgui/trans_background" );
+ new CBitmapImagePanel( pWindow, "LeftClear", "gfx/vgui/trans_background" );
+ new CBitmapImagePanel( pWindow, "RightClear", "gfx/vgui/trans_background" );
+
+ // Logo -----------------------------------------------
+ new CBitmapImagePanel( pWindow, "ExclamationPanel", "gfx/vgui/CS_logo" );
+
+ // Title caption --------------------------------------
+ Panel *pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" ));
+ if ( !pPanel )
+ new CaptionLabel( pWindow, "CaptionLabel", "" );
+}
+
+void ResizeWindowControls( EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY )
+{
+ if (!pWindow || !pWindow->GetBuildGroup() || !pWindow->GetBuildGroup()->GetPanelList())
+ return;
+
+ CUtlVector<PHandle> *panelList = pWindow->GetBuildGroup()->GetPanelList();
+ CUtlVector<Panel *> resizedPanels;
+ CUtlVector<Panel *> movedPanels;
+
+ // Resize to account for 1.25 aspect ratio (1280x1024) screens
+ {
+ for ( int i = 0; i < panelList->Size(); ++i )
+ {
+ PHandle handle = (*panelList)[i];
+
+ Panel *panel = handle.Get();
+
+ bool found = false;
+ for ( int j = 0; j < resizedPanels.Size(); ++j )
+ {
+ if (panel == resizedPanels[j])
+ found = true;
+ }
+
+ if (!panel || found)
+ {
+ continue;
+ }
+
+ resizedPanels.AddToTail( panel ); // don't move a panel more than once
+
+ if ( panel != pWindow )
+ {
+ RepositionControl( panel );
+ }
+ }
+ }
+
+ // and now re-center them. Woohoo!
+ for ( int i = 0; i < panelList->Size(); ++i )
+ {
+ PHandle handle = (*panelList)[i];
+
+ Panel *panel = handle.Get();
+
+ bool found = false;
+ for ( int j = 0; j < movedPanels.Size(); ++j )
+ {
+ if (panel == movedPanels[j])
+ found = true;
+ }
+
+ if (!panel || found)
+ {
+ continue;
+ }
+
+ movedPanels.AddToTail( panel ); // don't move a panel more than once
+
+ if ( panel != pWindow )
+ {
+ int x, y;
+
+ panel->GetPos( x, y );
+ panel->SetPos( x + offsetX, y + offsetY );
+
+#if DEBUG_WINDOW_REPOSITIONING
+ DevMsg( "Repositioning '%s' from (%d,%d) to (%d,%d) -- a distance of (%d,%d)\n",
+ panel->GetName(), x, y, x + offsetX, y + offsetY, offsetX, offsetY );
+#endif
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and
+// centers them on the screen. Sub-controls are also resized and moved.
+//-----------------------------------------------------------------------------
+void LayoutBackgroundPanel( EditablePanel *pWindow )
+{
+ if ( !pWindow )
+ return;
+
+ int screenW, screenH;
+ GetHudSize( screenW, screenH );
+
+ int wide, tall;
+ pWindow->GetSize( wide, tall );
+
+ int offsetX = 0;
+ int offsetY = 0;
+
+ // Slide everything over to the center
+ pWindow->SetBounds( 0, 0, screenW, screenH );
+
+ if ( wide != screenW || tall != screenH )
+ {
+ wide = GetAlternateProportionalValueFromScaled( pWindow->GetScheme(), wide);
+ tall = GetAlternateProportionalValueFromScaled( pWindow->GetScheme(), tall);
+
+ offsetX = (screenW - wide)/2;
+ offsetY = (screenH - tall)/2;
+
+ ResizeWindowControls( pWindow, tall, wide, offsetX, offsetY );
+ }
+
+ // now that the panels are moved/resized, look for some bg panels, and re-align them
+ FixupBackgroundPanels( pWindow, offsetX, offsetY );
+}
+
+//-----------------------------------------------------------------------------
+
diff --git a/game/client/cstrike/VGUI/backgroundpanel.h b/game/client/cstrike/VGUI/backgroundpanel.h
new file mode 100644
index 0000000..5edf22e
--- /dev/null
+++ b/game/client/cstrike/VGUI/backgroundpanel.h
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSBACKGROUND_H
+#define CSBACKGROUND_H
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/EditablePanel.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates background image panels
+//-----------------------------------------------------------------------------
+void CreateBackground( vgui::EditablePanel *pWindow );
+
+//-----------------------------------------------------------------------------
+// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and
+// centers them on the screen. Sub-controls are also resized and moved.
+//-----------------------------------------------------------------------------
+void LayoutBackgroundPanel( vgui::EditablePanel *pWindow );
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets colors etc for background image panels
+//-----------------------------------------------------------------------------
+void ApplyBackgroundSchemeSettings( vgui::EditablePanel *pWindow, vgui::IScheme *pScheme );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ResizeWindowControls( vgui::EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY );
+
+//-----------------------------------------------------------------------------
+// Purpose: transform a standard scaled value into one that is scaled based the minimum
+// of the horizontal and vertical ratios
+//-----------------------------------------------------------------------------
+int GetAlternateProportionalValueFromScaled( vgui::HScheme scheme, int scaledValue );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void DrawRoundedBackground( Color bgColor, int wide, int tall );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void DrawRoundedBorder( Color borderColor, int wide, int tall );
+
+//-----------------------------------------------------------------------------
+
+#endif // CSBACKGROUND_H
diff --git a/game/client/cstrike/VGUI/base_stats_page.cpp b/game/client/cstrike/VGUI/base_stats_page.cpp
new file mode 100644
index 0000000..ab27865
--- /dev/null
+++ b/game/client/cstrike/VGUI/base_stats_page.cpp
@@ -0,0 +1,359 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "tier3/tier3.h"
+#include "vgui/ILocalize.h"
+#include "lifetime_stats_page.h"
+#include <vgui_controls/SectionedListPanel.h>
+#include "cs_client_gamestats.h"
+#include "filesystem.h"
+#include "cs_weapon_parse.h"
+#include "buy_presets/buy_presets.h"
+#include "../vgui_controls/ScrollBar.h"
+#include "stat_card.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+KeyValues *g_pPreloadedCSBaseStatGroupLayout = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CBaseStatsPage::CBaseStatsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSBaseStatsDialog")
+{
+ vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ m_listItemFont = pScheme->GetFont( "StatsPageText", IsProportional() );
+
+ m_statsList = new SectionedListPanel( this, "StatsList" );
+ m_statsList->SetClickable(false);
+ m_statsList->SetDrawHeaders(false);
+
+ m_bottomBar = new ImagePanel(this, "BottomBar");
+
+ m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" );
+ m_pGroupsList->SetFirstColumnWidth( 0 );
+
+ SetBounds(0, 0, 900, 780);
+ SetMinimumSize( 256, 780 );
+
+ SetBgColor(GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme));
+
+ m_pStatCard = new StatCard(this, "ignored");
+
+ ListenForGameEvent( "player_stats_updated" );
+
+ m_bStatsDirty = true;
+}
+
+CBaseStatsPage::~CBaseStatsPage()
+{
+ delete m_statsList;
+}
+
+
+void CBaseStatsPage::MoveToFront()
+{
+ UpdateStatsData();
+ m_pStatCard->UpdateInfo();
+}
+
+void CBaseStatsPage::UpdateStatsData()
+{
+ // Hide the group list scrollbar
+ if (m_pGroupsList->GetScrollbar())
+ {
+ m_pGroupsList->GetScrollbar()->SetWide(0);
+ }
+
+ UpdateGroupPanels();
+ RepopulateStats();
+
+ m_bStatsDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from statsdialog.res in hl2/resource/ui/
+//-----------------------------------------------------------------------------
+void CBaseStatsPage::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings("resource/ui/CSBaseStatsDialog.res");
+
+ m_statsList->SetClickable(false);
+ m_statsList->SetDrawHeaders(false);
+
+ m_statsList->SetVerticalScrollbar(true);
+
+ SetBgColor(Color(86,86,86,255));
+
+ //Remove any pre-existing sections and add then fresh (this can happen on a resolution change)
+ m_statsList->RemoveAllSections();
+
+ m_statsList->AddSection( 0, "Players");
+
+ m_statsList->SetFontSection(0, m_listItemFont);
+
+ m_pGroupsList->SetBgColor(Color(86,86,86,255));
+ m_statsList->SetBgColor(Color(52,52,52,255));
+}
+
+void CBaseStatsPage::SetActiveStatGroup (CBaseStatGroupPanel* groupPanel)
+{
+ for (int i = 0; i < m_pGroupsList->GetItemCount(); i++)
+ {
+ CBaseStatGroupPanel *pPanel = (CBaseStatGroupPanel*)m_pGroupsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ if ( pPanel != groupPanel )
+ {
+ pPanel->SetGroupActive( false );
+ }
+ else
+ {
+ pPanel->SetGroupActive( true );
+ }
+ }
+ }
+}
+
+void CBaseStatsPage::UpdateGroupPanels()
+{
+ int iGroupCount = m_pGroupsList->GetItemCount();
+ vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() );
+
+ for ( int i = 0; i < iGroupCount; i++ )
+ {
+ CBaseStatGroupPanel *pPanel = (CBaseStatGroupPanel*)m_pGroupsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ pPanel->Update( pGroupScheme );
+ }
+ }
+}
+
+
+
+void CBaseStatsPage::OnSizeChanged(int newWide, int newTall)
+{
+ BaseClass::OnSizeChanged(newWide, newTall);
+
+ if (m_statsList)
+ {
+ int labelX, labelY, listX, listY, listWide, listTall;
+ m_statsList->GetBounds(listX, listY, listWide, listTall);
+
+ if (m_bottomBar)
+ {
+ m_bottomBar->GetPos(labelX, labelY);
+ m_bottomBar->SetPos(labelX, listY + listTall);
+ }
+ }
+}
+
+const wchar_t* CBaseStatsPage::TranslateWeaponKillIDToAlias( int statKillID )
+{
+ CSWeaponID weaponIDIndex = WEAPON_MAX;
+ for ( int i = 0; WeaponName_StatId_Table[i].killStatId != CSSTAT_UNDEFINED; ++i )
+ {
+ if( WeaponName_StatId_Table[i].killStatId == statKillID )
+ {
+ weaponIDIndex = WeaponName_StatId_Table[i].weaponId;
+ break;
+ }
+ }
+
+ if (weaponIDIndex == WEAPON_MAX)
+ {
+ return NULL;
+ }
+ else
+ {
+ return WeaponIDToDisplayName(weaponIDIndex);
+ }
+}
+
+const wchar_t* CBaseStatsPage::LocalizeTagOrUseDefault( const char* tag, const wchar_t* def )
+{
+ const wchar_t* result = g_pVGuiLocalize->Find( tag );
+
+ if ( !result )
+ result = def ? def : L"\0";
+
+ return result;
+}
+
+CBaseStatGroupPanel* CBaseStatsPage::AddGroup( const wchar_t* name, const char* title_tag, const wchar_t* def )
+{
+ CBaseStatGroupPanel* newGroup = new CBaseStatGroupPanel( m_pGroupsList, this, "StatGroupPanel", 0 );
+ newGroup->SetGroupInfo( name, LocalizeTagOrUseDefault( title_tag, def ) );
+ newGroup->SetGroupActive( false );
+
+ m_pGroupsList->AddItem( NULL, newGroup );
+
+ return newGroup;
+}
+
+void CBaseStatsPage::FireGameEvent( IGameEvent * event )
+{
+ const char *type = event->GetName();
+
+ if ( 0 == Q_strcmp( type, "player_stats_updated" ) )
+ m_bStatsDirty = true;
+}
+
+void CBaseStatsPage::OnThink()
+{
+ if ( m_bStatsDirty )
+ UpdateStatsData();
+}
+
+CBaseStatGroupPanel::CBaseStatGroupPanel( vgui::PanelListPanel *parent, CBaseStatsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name )
+{
+ m_pParent = parent;
+ m_pOwner = owner;
+ m_pSchemeSettings = NULL;
+
+ m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" ));
+ m_pBaseStatGroupLabel = new vgui::Label( this, "GroupName", "name" );
+ m_pGroupButton = new CBaseStatGroupButton(this, "GroupButton", "" );
+ m_pGroupButton->SetPos( 0, 0 );
+ m_pGroupButton->SetZPos( 20 );
+ m_pGroupButton->SetWide( 256 );
+ m_pGroupButton->SetTall( 64 );
+ SetMouseInputEnabled( true );
+ parent->SetMouseInputEnabled( true );
+
+ m_bActiveButton = false;
+}
+
+CBaseStatGroupPanel::~CBaseStatGroupPanel()
+{
+ delete m_pBaseStatGroupLabel;
+ delete m_pGroupIcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
+//-----------------------------------------------------------------------------
+bool CBaseStatGroupPanel::LoadIcon( const char* pFilename)
+{
+ char imagePath[_MAX_PATH];
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS );
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ char checkFile[_MAX_PATH];
+ Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
+ if ( !g_pFullFileSystem->FileExists( checkFile ) )
+ {
+ Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
+ }
+
+ m_pGroupIcon->SetShouldScaleImage( true );
+ m_pGroupIcon->SetImage( imagePath );
+ m_pGroupIcon->SetVisible( true );
+
+ return m_pGroupIcon->IsVisible();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from hl2/resource/ui/achievementitem.res
+// Sets display info for this achievement item.
+//-----------------------------------------------------------------------------
+void CBaseStatGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme )
+{
+ if ( !g_pPreloadedCSBaseStatGroupLayout )
+ {
+ PreloadResourceFile();
+ }
+
+ LoadControlSettings( "", NULL, g_pPreloadedCSBaseStatGroupLayout );
+
+ m_pSchemeSettings = pScheme;
+
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+void CBaseStatGroupPanel::Update( vgui::IScheme* pScheme )
+{
+ if ( m_pSchemeSettings )
+ {
+
+ // Set group name text
+ m_pBaseStatGroupLabel->SetText( m_pGroupTitle );
+ m_pBaseStatGroupLabel->SetFgColor(Color(157, 194, 80, 255));
+
+ if ( !m_bActiveButton )
+ {
+ LoadIcon( "achievement-btn-up" );
+ }
+ else
+ {
+ LoadIcon( "achievement-btn-select" );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseStatGroupPanel::PreloadResourceFile( void )
+{
+ const char *controlResourceName = "resource/ui/StatGroup.res";
+
+ g_pPreloadedCSBaseStatGroupLayout = new KeyValues(controlResourceName);
+ g_pPreloadedCSBaseStatGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Assigns a name and achievement id bounds for an achievement group.
+//-----------------------------------------------------------------------------
+void CBaseStatGroupPanel::SetGroupInfo ( const wchar_t* name, const wchar_t* title)
+{
+ // Store away the group name
+ short _textLen = (short)wcslen(name) + 1;
+ m_pGroupName = new wchar_t[_textLen];
+ Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) );
+
+ _textLen = (short)wcslen(title) + 1;
+ m_pGroupTitle = new wchar_t[_textLen];
+ Q_memcpy( m_pGroupTitle, title, _textLen * sizeof(wchar_t) );
+}
+
+
+CBaseStatGroupButton::CBaseStatGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
+BaseClass( pParent, pName, pText )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the case where the user presses an achievement group button.
+//-----------------------------------------------------------------------------
+void CBaseStatGroupButton::DoClick( void )
+{
+ // Process when a group button is hit
+ CBaseStatGroupPanel* pParent = static_cast<CBaseStatGroupPanel*>(GetParent());
+
+ if (pParent)
+ {
+ CBaseStatsPage* pBaseStatsPage = static_cast<CBaseStatsPage*>(pParent->GetOwner());
+
+ if (pBaseStatsPage)
+ {
+ pBaseStatsPage->SetActiveStatGroup( pParent );
+ pBaseStatsPage->UpdateStatsData();
+ }
+ }
+}
diff --git a/game/client/cstrike/VGUI/base_stats_page.h b/game/client/cstrike/VGUI/base_stats_page.h
new file mode 100644
index 0000000..e22ec32
--- /dev/null
+++ b/game/client/cstrike/VGUI/base_stats_page.h
@@ -0,0 +1,135 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSBASESTATSPAGE_H
+#define CSBASESTATSPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/PropertyPage.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/ImagePanel.h"
+#include "GameEventListener.h"
+
+struct PlayerStatData_t;
+class IScheme;
+class CBaseStatGroupPanel;
+class StatCard;
+struct StatsCollection_t;
+struct RoundStatsDirectAverage_t;
+
+class CBaseStatsPage : public vgui::PropertyPage, public CGameEventListener
+{
+ DECLARE_CLASS_SIMPLE ( CBaseStatsPage, vgui::PropertyPage );
+
+public:
+ CBaseStatsPage( vgui::Panel *parent, const char *name );
+
+ ~CBaseStatsPage();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void MoveToFront();
+ virtual void OnSizeChanged(int wide, int tall);
+ virtual void OnThink();
+
+ void UpdateStatsData();
+ void SetActiveStatGroup (CBaseStatGroupPanel* groupPanel);
+
+ virtual void FireGameEvent( IGameEvent * event );
+
+protected:
+
+ void UpdateGroupPanels();
+ CBaseStatGroupPanel* AddGroup( const wchar_t* name, const char* title_tag, const wchar_t* def = NULL );
+ const wchar_t* TranslateWeaponKillIDToAlias( int statKillID );
+ const wchar_t* LocalizeTagOrUseDefault( const char* tag, const wchar_t* def = NULL );
+
+ virtual void RepopulateStats() = 0;
+
+ vgui::SectionedListPanel *m_statsList;
+ vgui::HFont m_listItemFont;
+
+private:
+
+ vgui::PanelListPanel *m_pGroupsList;
+ vgui::ImagePanel* m_bottomBar;
+ StatCard* m_pStatCard;
+ bool m_bStatsDirty;
+};
+
+
+
+
+class CBaseStatGroupButton : public vgui::Button
+{
+ DECLARE_CLASS_SIMPLE( CBaseStatGroupButton, vgui::Button );
+
+public:
+
+ CBaseStatGroupButton( vgui::Panel *pParent, const char *pName, const char *pText );
+
+ virtual void DoClick( void );
+};
+
+
+
+
+
+class CBaseStatGroupPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CBaseStatGroupPanel, vgui::EditablePanel );
+
+public:
+ CBaseStatGroupPanel( vgui::PanelListPanel *parent, CBaseStatsPage *owner, const char* name, int iListItemID );
+ ~CBaseStatGroupPanel();
+
+ void SetGroupInfo ( const wchar_t* name, const wchar_t* title);
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ void Update( vgui::IScheme* pScheme );
+
+ vgui::PanelListPanel* GetParent() { return m_pParent; }
+ CBaseStatsPage* GetOwner() { return m_pOwner; }
+
+ void SetGroupActive(bool active) { m_bActiveButton = active; }
+ bool IsGroupActive() { return m_bActiveButton; }
+
+protected:
+
+ // Loads an icon into a specified image panel, or turns the panel off if no icon was found.
+ bool LoadIcon( const char* pFilename);
+
+private:
+ void PreloadResourceFile( void );
+
+ vgui::PanelListPanel *m_pParent;
+ CBaseStatsPage *m_pOwner;
+
+ vgui::Label *m_pBaseStatGroupLabel;
+
+ CBaseStatGroupButton *m_pGroupButton;
+
+ vgui::ImagePanel *m_pGroupIcon;
+
+ vgui::IScheme *m_pSchemeSettings;
+
+ bool m_bActiveButton;
+
+ wchar_t *m_pGroupName;
+ wchar_t *m_pGroupTitle;
+};
+
+
+
+
+
+#endif // CSBASESTATSPAGE_H
diff --git a/game/client/cstrike/VGUI/bordered_panel.cpp b/game/client/cstrike/VGUI/bordered_panel.cpp
new file mode 100644
index 0000000..cec1d70
--- /dev/null
+++ b/game/client/cstrike/VGUI/bordered_panel.cpp
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//-------------------------------------------------------------
+// File: BorderedPanel.cpp
+// Desc:
+// Author: Peter Freese <[email protected]>
+// Date: 2009/05/20
+// Copyright: � 2009 Hidden Path Entertainment
+//-------------------------------------------------------------
+
+#include "cbase.h"
+#include "bordered_panel.h"
+#include "backgroundpanel.h" // rounded border support
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+void BorderedPanel::PaintBackground()
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ DrawRoundedBackground( GetBgColor(), wide, tall );
+ DrawRoundedBorder( GetFgColor(), wide, tall );
+}
+
+DECLARE_BUILD_FACTORY( BorderedPanel );
+
diff --git a/game/client/cstrike/VGUI/bordered_panel.h b/game/client/cstrike/VGUI/bordered_panel.h
new file mode 100644
index 0000000..7279f10
--- /dev/null
+++ b/game/client/cstrike/VGUI/bordered_panel.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//-------------------------------------------------------------
+// File: bordered_panel.h
+// Desc:
+// Author: Peter Freese <[email protected]>
+// Date: 2009/05/20
+// Copyright: � 2009 Hidden Path Entertainment
+//-------------------------------------------------------------
+
+#ifndef INCLUDED_BorderedPanel
+#define INCLUDED_BorderedPanel
+#pragma once
+
+#include <vgui_controls/EditablePanel.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Editable panel with a forced rounded/outlined border
+//-----------------------------------------------------------------------------
+class BorderedPanel : public EditablePanel
+{
+public:
+ DECLARE_CLASS_SIMPLE( BorderedPanel, EditablePanel );
+
+ BorderedPanel( Panel *parent, const char *name ) :
+ EditablePanel( parent, name )
+ {
+ }
+
+ void PaintBackground();
+};
+
+
+#endif // INCLUDED_BorderedPanel
diff --git a/game/client/cstrike/VGUI/buymouseoverpanelbutton.h b/game/client/cstrike/VGUI/buymouseoverpanelbutton.h
new file mode 100644
index 0000000..9e5abbf
--- /dev/null
+++ b/game/client/cstrike/VGUI/buymouseoverpanelbutton.h
@@ -0,0 +1,397 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BUYMOUSEOVERPANELBUTTON_H
+#define BUYMOUSEOVERPANELBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+#include <filesystem.h>
+#include "mouseoverpanelbutton.h"
+#include "hud.h"
+#include "c_cs_player.h"
+#include "cs_gamerules.h"
+#include "cstrike/bot/shared_util.h"
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui_controls/ImagePanel.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Triggers a new panel when the mouse goes over the button
+//-----------------------------------------------------------------------------
+class BuyMouseOverPanelButton : public MouseOverPanelButton
+{
+private:
+ typedef MouseOverPanelButton BaseClass;
+public:
+ BuyMouseOverPanelButton(vgui::Panel *parent, const char *panelName, vgui::EditablePanel *panel) :
+ MouseOverPanelButton( parent, panelName, panel)
+ {
+ m_iPrice = 0;
+ m_iPreviousPrice = 0;
+ m_iASRestrict = 0;
+ m_iDEUseOnly = 0;
+ m_command = NULL;
+ m_bIsBargain = false;
+
+ m_pBlackMarketPrice = NULL;//new EditablePanel( parent, "BlackMarket_Labels" );
+ if ( m_pBlackMarketPrice )
+ {
+ m_pBlackMarketPrice->LoadControlSettings( "Resource/UI/BlackMarket_Labels.res" );
+
+ int x,y,wide,tall;
+ GetClassPanel()->GetBounds( x, y, wide, tall );
+ m_pBlackMarketPrice->SetBounds( x, y, wide, tall );
+ int px, py;
+ GetClassPanel()->GetPinOffset( px, py );
+ int rx, ry;
+ GetClassPanel()->GetResizeOffset( rx, ry );
+ // Apply pin settings from template, too
+ m_pBlackMarketPrice->SetAutoResize( GetClassPanel()->GetPinCorner(), GetClassPanel()->GetAutoResize(), px, py, rx, ry );
+ }
+ }
+
+ virtual void ApplySettings( KeyValues *resourceData )
+ {
+ BaseClass::ApplySettings( resourceData );
+
+ KeyValues *kv = resourceData->FindKey( "cost", false );
+ if( kv ) // if this button has a cost defined for it
+ {
+ m_iPrice = kv->GetInt(); // save the price away
+ }
+
+ kv = resourceData->FindKey( "as_restrict", false );
+ if( kv ) // if this button has a map limitation for it
+ {
+ m_iASRestrict = kv->GetInt(); // save the as_restrict away
+ }
+
+ kv = resourceData->FindKey( "de_useonly", false );
+ if( kv ) // if this button has a map limitation for it
+ {
+ m_iDEUseOnly = kv->GetInt(); // save the de_useonly away
+ }
+
+ if ( m_command )
+ {
+ delete[] m_command;
+ m_command = NULL;
+ }
+ kv = resourceData->FindKey( "command", false );
+ if ( kv )
+ {
+ m_command = CloneString( kv->GetString() );
+ }
+
+ SetPriceState();
+ SetMapTypeState();
+ }
+
+ int GetASRestrict() { return m_iASRestrict; }
+
+ int GetDEUseOnly() { return m_iDEUseOnly; }
+
+ virtual void PerformLayout()
+ {
+ BaseClass::PerformLayout();
+ SetPriceState();
+ SetMapTypeState();
+
+#ifndef CS_SHIELD_ENABLED
+ if ( !Q_stricmp( GetName(), "shield" ) )
+ {
+ SetVisible( false );
+ SetEnabled( false );
+ }
+#endif
+ }
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_avaliableColor = pScheme->GetColor( "Label.TextColor", Color( 0, 0, 0, 0 ) );
+ m_unavailableColor = pScheme->GetColor( "Label.DisabledFgColor2", Color( 0, 0, 0, 0 ) );
+ m_bargainColor = Color( 0, 255, 0, 192 );
+
+ SetPriceState();
+ SetMapTypeState();
+ }
+
+ void SetPriceState()
+ {
+ if ( CSGameRules() && CSGameRules()->IsBlackMarket() )
+ {
+ SetMarketState();
+ }
+ else
+ {
+ if ( GetParent() )
+ {
+ Panel *pPanel = dynamic_cast< Panel * >(GetParent()->FindChildByName( "MarketSticker" ) );
+
+ if ( pPanel )
+ {
+ pPanel->SetVisible( false );
+ }
+ }
+
+ m_bIsBargain = false;
+ }
+
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( m_iPrice && ( pPlayer && m_iPrice > pPlayer->GetAccount() ) )
+ {
+ SetFgColor( m_unavailableColor );
+ SetCommand( "buy_unavailable" );
+ }
+ else
+ {
+ if ( m_bIsBargain == false )
+ {
+ SetFgColor( m_avaliableColor );
+ }
+ else
+ {
+ SetFgColor( m_bargainColor );
+ }
+
+ SetCommand( m_command );
+ }
+ }
+
+ void SetMarketState( void )
+ {
+ Panel *pClassPanel = GetClassPanel();
+ if ( pClassPanel )
+ {
+ pClassPanel->SetVisible( false );
+ }
+
+ if ( m_pBlackMarketPrice )
+ {
+ Label *pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "pricelabel" ) );
+
+ if ( pLabel )
+ {
+ const int BufLen = 2048;
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketPreviousPrice");
+
+ if ( !formatStr )
+ formatStr = L"%s1";
+
+ char strPrice[16];
+ wchar_t szPrice[64];
+ Q_snprintf( strPrice, sizeof( strPrice ), "%d", m_iPreviousPrice );
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice));
+
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice );
+ pLabel->SetText( wbuf );
+ pLabel->SetVisible( true );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "price" ) );
+
+ if ( pLabel )
+ {
+ const int BufLen = 2048;
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketCurrentPrice");
+
+ if ( !formatStr )
+ formatStr = L"%s1";
+
+ char strPrice[16];
+ wchar_t szPrice[64];
+ Q_snprintf( strPrice, sizeof( strPrice ), "%d", m_iPrice );
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice));
+
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice );
+ pLabel->SetText( wbuf );
+ pLabel->SetVisible( true );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "difference" ) );
+
+ if ( pLabel )
+ {
+ const int BufLen = 2048;
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketDeltaPrice");
+
+ if ( !formatStr )
+ formatStr = L"%s1";
+
+ char strPrice[16];
+ wchar_t szPrice[64];
+
+ int iDifference = m_iPreviousPrice - m_iPrice;
+
+ if ( iDifference >= 0 )
+ {
+ pLabel->SetFgColor( m_bargainColor );
+ }
+ else
+ {
+ pLabel->SetFgColor( Color( 192, 28, 0, 255 ) );
+ }
+
+ Q_snprintf( strPrice, sizeof( strPrice ), "%d", abs( iDifference ) );
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice));
+
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice );
+ pLabel->SetText( wbuf );
+ pLabel->SetVisible( true );
+ }
+
+ ImagePanel *pImage = dynamic_cast< ImagePanel * >(m_pBlackMarketPrice->FindChildByName( "classimage" ) );
+
+ if ( pImage )
+ {
+ ImagePanel *pClassImage = dynamic_cast< ImagePanel * >(GetClassPanel()->FindChildByName( "classimage" ) );
+
+ if ( pClassImage )
+ {
+ pImage->SetSize( pClassImage->GetWide(), pClassImage->GetTall() );
+ pImage->SetImage( pClassImage->GetImage() );
+ }
+ }
+
+ if ( GetParent() )
+ {
+ Panel *pPanel = dynamic_cast< Panel * >(GetParent()->FindChildByName( "MarketSticker" ) );
+
+ if ( pPanel )
+ {
+ if ( m_bIsBargain )
+ {
+ pPanel->SetVisible( true );
+ }
+ else
+ {
+ pPanel->SetVisible( false );
+ }
+ }
+ }
+ }
+ }
+
+ void SetMapTypeState()
+ {
+ CCSGameRules *pRules = CSGameRules();
+
+ if ( pRules )
+ {
+ if( pRules->IsVIPMap() )
+ {
+ if ( m_iASRestrict )
+ {
+ SetFgColor( m_unavailableColor );
+ SetCommand( "buy_unavailable" );
+ }
+ }
+
+ if ( !pRules->IsBombDefuseMap() )
+ {
+ if ( m_iDEUseOnly )
+ {
+ SetFgColor( m_unavailableColor );
+ SetCommand( "buy_unavailable" );
+ }
+ }
+ }
+ }
+
+ void SetBargainButton( bool state )
+ {
+ m_bIsBargain = state;
+ }
+
+ void SetCurrentPrice( int iPrice )
+ {
+ m_iPrice = iPrice;
+ }
+
+ void SetPreviousPrice( int iPrice )
+ {
+ m_iPreviousPrice = iPrice;
+ }
+
+ const char *GetBuyCommand( void )
+ {
+ return m_command;
+ }
+
+ virtual void ShowPage()
+ {
+ if ( g_lastPanel )
+ {
+ for( int i = 0; i< g_lastPanel->GetParent()->GetChildCount(); i++ )
+ {
+ MouseOverPanelButton *buyButton = dynamic_cast<MouseOverPanelButton *>(g_lastPanel->GetParent()->GetChild(i));
+
+ if ( buyButton )
+ {
+ buyButton->HidePage();
+ }
+ }
+ }
+
+ BaseClass::ShowPage();
+
+ if ( !Q_stricmp( m_command, "vguicancel" ) )
+ return;
+
+ if ( CSGameRules() && CSGameRules()->IsBlackMarket() )
+ {
+ if ( m_pBlackMarketPrice && !m_pBlackMarketPrice->IsVisible() )
+ {
+ m_pBlackMarketPrice->SetVisible( true );
+ }
+ }
+ }
+
+ virtual void HidePage()
+ {
+ BaseClass::HidePage();
+
+ if ( m_pBlackMarketPrice && m_pBlackMarketPrice->IsVisible() )
+ {
+ m_pBlackMarketPrice->SetVisible( false );
+ }
+ }
+
+private:
+
+ int m_iPrice;
+ int m_iPreviousPrice;
+ int m_iASRestrict;
+ int m_iDEUseOnly;
+ bool m_bIsBargain;
+
+ Color m_avaliableColor;
+ Color m_unavailableColor;
+ Color m_bargainColor;
+
+ char *m_command;
+
+public:
+ vgui::EditablePanel *m_pBlackMarketPrice;
+};
+
+
+#endif // BUYMOUSEOVERPANELBUTTON_H
diff --git a/game/client/cstrike/VGUI/buypreset_imageinfo.cpp b/game/client/cstrike/VGUI/buypreset_imageinfo.cpp
new file mode 100644
index 0000000..69f93cc
--- /dev/null
+++ b/game/client/cstrike/VGUI/buypreset_imageinfo.cpp
@@ -0,0 +1,577 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#include "weapon_csbase.h"
+#include "cs_ammodef.h"
+
+#include <vgui/IVGui.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/Label.h>
+#include <vgui/ILocalize.h>
+#include "vgui_controls/BuildGroup.h"
+#include "vgui_controls/BitmapImagePanel.h"
+#include "vgui_controls/TextEntry.h"
+#include "vgui_controls/TextImage.h"
+#include "vgui_controls/RichText.h"
+#include "vgui_controls/QueryBox.h"
+#include "career_box.h"
+#include "buypreset_listbox.h"
+#include "buypreset_weaponsetlabel.h"
+
+#include "cstrike/bot/shared_util.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+WeaponImageInfo::WeaponImageInfo()
+{
+ m_needLayout = m_isCentered = false;
+ m_left = m_top = m_wide = m_tall = 0;
+ m_isPrimary = false;
+ memset( &m_weapon, 0, sizeof(ImageInfo) );
+ memset( &m_ammo, 0, sizeof(ImageInfo) );
+ m_weaponScale = m_ammoScale = 0;
+ m_pAmmoText = new TextImage( "" );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+WeaponImageInfo::~WeaponImageInfo()
+{
+ delete m_pAmmoText;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional )
+{
+ Color color = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) );
+
+ m_pAmmoText->SetColor( color );
+ m_pAmmoText->SetFont( pScheme->GetFont( "Default", isProportional ) );
+ m_pAmmoText->SetWrap( false );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::SetBounds( int left, int top, int wide, int tall )
+{
+ m_left = left;
+ m_top = top;
+ m_wide = wide;
+ m_tall = tall;
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::SetCentered( bool isCentered )
+{
+ m_isCentered = isCentered;
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::SetScaleAt1024( int weaponScale, int ammoScale )
+{
+ m_weaponScale = weaponScale;
+ m_ammoScale = ammoScale;
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool useCurrentAmmoType )
+{
+ m_pAmmoText->SetText( L"" );
+ m_weapon.image = NULL;
+ m_ammo.image = NULL;
+ m_isPrimary = isPrimary;
+
+ if ( !pWeapon )
+ return;
+
+ wchar_t *multiplierString = g_pVGuiLocalize->Find("#Cstrike_BuyMenuPresetMultiplier");
+ if ( !multiplierString )
+ multiplierString = L"";
+ const int BufLen = 32;
+ wchar_t buf[BufLen];
+
+ if ( pWeapon->GetAmmoType() == AMMO_CLIPS )
+ {
+ CSWeaponID weaponID = pWeapon->GetWeaponID();
+ const CCSWeaponInfo *info = GetWeaponInfo( weaponID );
+ int numClips = pWeapon->GetAmmoAmount();
+ if ( info )
+ {
+ int maxRounds = GetCSAmmoDef()->MaxCarry( info->iAmmoType );
+ int buyClipSize = GetCSAmmoDef()->GetBuySize( info->iAmmoType );
+
+ int maxClips = (buyClipSize > 0) ? ceil(maxRounds/(float)buyClipSize) : 0;
+ numClips = MIN( numClips, maxClips );
+ m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( weaponID, m_isPrimary ), true );
+ if ( numClips == 0 )
+ {
+ m_ammo.image = NULL;
+ }
+ else if ( info->m_WeaponType == WEAPONTYPE_SHOTGUN )
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/shell", true );
+ }
+ else if ( isPrimary )
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true );
+ }
+ else
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true );
+ }
+
+ if ( numClips > 1 )
+ {
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( numClips ) );
+ m_pAmmoText->SetText( buf );
+ }
+ else
+ {
+ m_pAmmoText->SetText( L"" );
+ }
+ }
+ else if ( numClips > 0 || !useCurrentAmmoType )
+ {
+ if ( useCurrentAmmoType )
+ {
+ CSWeaponID currentID = GetClientWeaponID( isPrimary );
+ m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( currentID, m_isPrimary ), true );
+ info = GetWeaponInfo( currentID );
+ if ( !info )
+ {
+ m_weapon.image = NULL;
+ numClips = 0;
+ }
+ else if ( info->m_WeaponType == WEAPONTYPE_SHOTGUN )
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/shell", true );
+ }
+ else if ( isPrimary )
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true );
+ }
+ else
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true );
+ }
+ }
+ else
+ {
+ m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( weaponID, m_isPrimary ), true );
+ if ( numClips == 0 )
+ {
+ m_ammo.image = NULL;
+ }
+ else if ( isPrimary )
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true );
+ }
+ else
+ {
+ m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true );
+ }
+ }
+ if ( numClips > 1 )
+ {
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( numClips ) );
+ m_pAmmoText->SetText( buf );
+ }
+ else
+ {
+ m_pAmmoText->SetText( L"" );
+ }
+ }
+ }
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::Paint()
+{
+ if ( m_needLayout )
+ PerformLayout();
+
+ m_weapon.Paint();
+ m_ammo.Paint();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::PaintText()
+{
+ if ( m_needLayout )
+ PerformLayout();
+
+ m_pAmmoText->Paint();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponImageInfo::PerformLayout()
+{
+ m_needLayout = false;
+
+ m_weapon.FitInBounds( m_left, m_top, m_wide*0.8, m_tall, m_isCentered, m_weaponScale );
+ int ammoX = MIN( m_wide*5/6, m_weapon.w );
+ int ammoSize = m_tall * 9 / 16;
+ if ( !m_isPrimary )
+ {
+ ammoSize = ammoSize * 25 / 40;
+ ammoX = MIN( m_wide*5/6, m_weapon.w*3/4 );
+ }
+ if ( ammoX + ammoSize > m_wide )
+ {
+ ammoX = m_wide - ammoSize;
+ }
+ m_ammo.FitInBounds( m_left + ammoX, m_top + m_tall - ammoSize, ammoSize, ammoSize, false, m_ammoScale );
+
+ int w, h;
+ m_pAmmoText->ResizeImageToContent();
+ m_pAmmoText->GetSize( w, h );
+ if ( m_isPrimary )
+ {
+ if ( m_ammoScale < 75 )
+ {
+ m_pAmmoText->SetPos( m_left + ammoX + ammoSize*1.25f - w, m_top + m_tall - h );
+ }
+ else
+ {
+ m_pAmmoText->SetPos( m_left + ammoX + ammoSize - w, m_top + m_tall - h );
+ }
+ }
+ else
+ {
+ m_pAmmoText->SetPos( m_left + ammoX + ammoSize, m_top + m_tall - h );
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+WeaponLabel::WeaponLabel(Panel *parent, const char *panelName) : BaseClass( parent, panelName )
+{
+ SetSize( 10, 10 );
+ SetMouseInputEnabled( false );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+WeaponLabel::~WeaponLabel()
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponLabel::SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool showAmmo )
+{
+ BuyPresetWeapon weapon(WEAPON_NONE);
+ if ( pWeapon )
+ weapon = *pWeapon;
+ if ( !showAmmo )
+ weapon.SetAmmoAmount( 0 );
+ m_weapon.SetWeapon( &weapon, isPrimary, false );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponLabel::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_weapon.ApplyTextSettings( pScheme, IsProportional() );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponLabel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int wide, tall;
+ GetSize( wide, tall );
+ m_weapon.SetBounds( 0, 0, wide, tall );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void WeaponLabel::Paint()
+{
+ BaseClass::Paint();
+
+ m_weapon.Paint();
+ m_weapon.PaintText();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+ItemImageInfo::ItemImageInfo()
+{
+ m_needLayout = false;
+ m_left = m_top = m_wide = m_tall = 0;
+ m_count = 0;
+ memset( &m_image, 0, sizeof(ImageInfo) );
+ m_pText = new TextImage( "" );
+
+ SetBounds( 0, 0, 100, 100 );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+ItemImageInfo::~ItemImageInfo()
+{
+ delete m_pText;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional )
+{
+ Color color = pScheme->GetColor( "Label.TextColor", Color( 0, 0, 0, 0 ) );
+
+ m_pText->SetColor( color );
+ m_pText->SetFont( pScheme->GetFont( "Default", isProportional ) );
+ m_pText->SetWrap( false );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::SetBounds( int left, int top, int wide, int tall )
+{
+ m_left = left;
+ m_top = top;
+ m_wide = wide;
+ m_tall = tall;
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::SetItem( const char *imageFname, int count )
+{
+ m_pText->SetText( L"" );
+ m_count = count;
+
+ if ( imageFname )
+ m_image.image = scheme()->GetImage( imageFname, true );
+ else
+ m_image.image = NULL;
+
+ if ( count > 1 )
+ {
+ wchar_t *multiplierString = g_pVGuiLocalize->Find("#Cstrike_BuyMenuPresetMultiplier");
+ if ( !multiplierString )
+ multiplierString = L"";
+ const int BufLen = 32;
+ wchar_t buf[BufLen];
+
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( count ) );
+ m_pText->SetText( buf );
+ }
+ m_needLayout = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::Paint()
+{
+ if ( m_needLayout )
+ PerformLayout();
+
+ if ( m_count )
+ m_image.Paint();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::PaintText()
+{
+ if ( m_needLayout )
+ PerformLayout();
+
+ m_pText->Paint();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ItemImageInfo::PerformLayout()
+{
+ m_needLayout = false;
+
+ m_image.FitInBounds( m_left, m_top, m_wide, m_tall, false, 0 );
+
+ int w, h;
+ m_pText->ResizeImageToContent();
+ m_pText->GetSize( w, h );
+ m_pText->SetPos( m_left + m_image.w - w, m_top + m_tall - h );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+EquipmentLabel::EquipmentLabel(Panel *parent, const char *panelName, const char *imageFname) : BaseClass( parent, panelName )
+{
+ SetSize( 10, 10 );
+ m_item.SetItem( imageFname, 0 );
+ SetMouseInputEnabled( false );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+EquipmentLabel::~EquipmentLabel()
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void EquipmentLabel::SetItem( const char *imageFname, int count )
+{
+ m_item.SetItem( imageFname, count );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void EquipmentLabel::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_item.ApplyTextSettings( pScheme, IsProportional() );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void EquipmentLabel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int wide, tall;
+ GetSize( wide, tall );
+ m_item.SetBounds( 0, 0, wide, tall );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void EquipmentLabel::Paint()
+{
+ BaseClass::Paint();
+
+ m_item.Paint();
+ m_item.PaintText();
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+/// Helper function: draws a simple dashed line
+void DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen)
+{
+ // work out which way the line goes
+ if ((x1 - x0) > (y1 - y0))
+ {
+ // x direction line
+ while (1)
+ {
+ if (x0 + dashLen > x1)
+ {
+ // draw partial
+ surface()->DrawFilledRect(x0, y0, x1, y1+1);
+ }
+ else
+ {
+ surface()->DrawFilledRect(x0, y0, x0 + dashLen, y1+1);
+ }
+
+ x0 += dashLen;
+
+ if (x0 + gapLen > x1)
+ break;
+
+ x0 += gapLen;
+ }
+ }
+ else
+ {
+ // y direction
+ while (1)
+ {
+ if (y0 + dashLen > y1)
+ {
+ // draw partial
+ surface()->DrawFilledRect(x0, y0, x1+1, y1);
+ }
+ else
+ {
+ surface()->DrawFilledRect(x0, y0, x1+1, y0 + dashLen);
+ }
+
+ y0 += dashLen;
+
+ if (y0 + gapLen > y1)
+ break;
+
+ y0 += gapLen;
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+void ImageInfo::Paint()
+{
+ if ( !image )
+ return;
+
+ image->SetSize( w, h );
+ image->SetPos( x, y );
+ image->Paint();
+ image->SetSize( 0, 0 ); // restore image size to content size to not mess up other places that use the same image
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void ImageInfo::FitInBounds( int baseX, int baseY, int width, int height, bool center, int scaleAt1024, bool halfHeight )
+{
+ if ( !image )
+ {
+ x = y = w = h = 0;
+ return;
+ }
+
+ image->GetContentSize(fullW, fullH);
+
+ if ( scaleAt1024 )
+ {
+ int screenW, screenH;
+ GetHudSize( screenW, screenH );
+
+ w = fullW * screenW / 1024 * scaleAt1024 / 100;
+ h = fullH * screenW / 1024 * scaleAt1024 / 100;
+
+ if ( fullH > 64 && scaleAt1024 == 100 )
+ {
+ w = w * 64 / fullH;
+ h = h * 64 / fullH;
+ }
+
+ if ( h > height * 1.2 )
+ scaleAt1024 = 0;
+ }
+ if ( !scaleAt1024 )
+ {
+ w = fullW;
+ h = fullH;
+
+ if ( h != height )
+ {
+ w = (int) w * 1.0f * height / h;
+ h = height;
+ }
+
+ if ( w > width )
+ {
+ h = (int) h * 1.0f * width / w;
+ w = width;
+ }
+ }
+
+ if ( center )
+ {
+ x = baseX + (width - w)/2;
+ }
+ else
+ {
+ x = baseX;
+ }
+ y = baseY + (height - h)/2;
+}
+
+//--------------------------------------------------------------------------------------------------------------
diff --git a/game/client/cstrike/VGUI/buypreset_listbox.cpp b/game/client/cstrike/VGUI/buypreset_listbox.cpp
new file mode 100644
index 0000000..add8dd7
--- /dev/null
+++ b/game/client/cstrike/VGUI/buypreset_listbox.cpp
@@ -0,0 +1,406 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#include <KeyValues.h>
+#include <vgui/MouseCode.h>
+#include <vgui/IInput.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+
+#include <vgui_controls/EditablePanel.h>
+#include <vgui_controls/ScrollBar.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/Controls.h>
+#include "buypreset_listbox.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+BuyPresetListBox::BuyPresetListBox( vgui::Panel *parent, char const *panelName ) : Panel( parent, panelName )
+{
+ m_visibleIndex = 0;
+ m_lastSize = 0;
+
+ SetBounds( 0, 0, 100, 100 );
+
+ m_vbar = new ScrollBar(this, "PanelListPanelVScroll", true);
+ m_vbar->SetBounds( 0, 0, 20, 20 );
+ m_vbar->SetVisible(true);
+ m_vbar->AddActionSignalTarget( this );
+
+ m_pPanelEmbedded = new EditablePanel(this, "PanelListEmbedded");
+ m_pPanelEmbedded->SetBounds(0, 0, 20, 20);
+ m_pPanelEmbedded->SetPaintBackgroundEnabled( false );
+ m_pPanelEmbedded->SetPaintBorderEnabled(false);
+
+ if( IsProportional() )
+ {
+ int width, height;
+ int sw,sh;
+ surface()->GetProportionalBase( width, height );
+ GetHudSize(sw, sh);
+
+ // resize scrollbar, etc
+ m_iScrollbarSize = static_cast<int>( static_cast<float>( SCROLLBAR_SIZE )*( static_cast<float>( sw )/ static_cast<float>( width )));
+ m_iDefaultHeight = static_cast<int>( static_cast<float>( DEFAULT_HEIGHT )*( static_cast<float>( sw )/ static_cast<float>( width )));
+ m_iPanelBuffer = static_cast<int>( static_cast<float>( PANELBUFFER )*( static_cast<float>( sw )/ static_cast<float>( width )));
+ }
+ else
+ {
+ m_iScrollbarSize = SCROLLBAR_SIZE;
+ m_iDefaultHeight = DEFAULT_HEIGHT;
+ m_iPanelBuffer = PANELBUFFER;
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+BuyPresetListBox::~BuyPresetListBox()
+{
+ // free data from table
+ DeleteAllItems();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Passes commands up to the parent
+ */
+void BuyPresetListBox::OnCommand( const char *command )
+{
+ GetParent()->OnCommand( command );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Scrolls the list according to the mouse wheel movement
+ */
+void BuyPresetListBox::OnMouseWheeled(int delta)
+{
+ int scale = 3;
+ if ( m_items.Count() )
+ {
+ Panel *panel = m_items[0].panel;
+ if ( panel )
+ {
+ scale = panel->GetTall() + m_iPanelBuffer;
+ }
+ }
+ int val = m_vbar->GetValue();
+ val -= (delta * scale);
+ m_vbar->SetValue(val);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Computes vertical pixels needed by listbox contents
+ */
+int BuyPresetListBox::computeVPixelsNeeded( void )
+{
+ int pixels = 0;
+
+ int i;
+ for ( i = 0; i < m_items.Count(); i++ )
+ {
+ Panel *panel = m_items[i].panel;
+ if ( !panel )
+ continue;
+
+ int w, h;
+ panel->GetSize( w, h );
+
+ pixels += m_iPanelBuffer; // add in buffer. between items.
+ pixels += h;
+ }
+
+ pixels += m_iPanelBuffer; // add in buffer below last item
+
+ return pixels;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Adds an item to the end of the listbox. UserData is assumed to be a pointer that can be freed by the listbox if non-NULL.
+ */
+int BuyPresetListBox::AddItem( vgui::Panel *panel, void * userData )
+{
+ assert(panel);
+
+ DataItem item = { panel, userData };
+
+ panel->SetParent( m_pPanelEmbedded );
+
+ m_items.AddToTail( item );
+
+ InvalidateLayout();
+ return m_items.Count();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Exchanges two items in the listbox
+ */
+void BuyPresetListBox::SwapItems( int index1, int index2 )
+{
+ if ( index1 < 0 || index2 < 0 || index1 >= m_items.Count() || index2 >= m_items.Count() )
+ {
+ return;
+ }
+
+ DataItem temp = m_items[index1];
+ m_items[index1] = m_items[index2];
+ m_items[index2] = temp;
+
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Returns the number of items in the listbox
+ */
+int BuyPresetListBox::GetItemCount( void ) const
+{
+ return m_items.Count();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Returns the panel in the given index, or NULL
+ */
+Panel * BuyPresetListBox::GetItemPanel(int index) const
+{
+ if ( index < 0 || index >= m_items.Count() )
+ return NULL;
+
+ return m_items[index].panel;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Returns the userData in the given index, or NULL
+ */
+void * BuyPresetListBox::GetItemUserData(int index)
+{
+ if ( index < 0 || index >= m_items.Count() )
+ {
+ return NULL;
+ }
+
+ return m_items[index].userData;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Sets the userData in the given index
+ */
+void BuyPresetListBox::SetItemUserData( int index, void * userData )
+{
+ if ( index < 0 || index >= m_items.Count() )
+ return;
+
+ m_items[index].userData = userData;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Removes an item from the table (changing the indices of all following items), deleting the panel and userData
+ */
+void BuyPresetListBox::RemoveItem(int index)
+{
+ if ( index < 0 || index >= m_items.Count() )
+ return;
+
+ DataItem item = m_items[index];
+ if ( item.panel )
+ {
+ item.panel->MarkForDeletion();
+ }
+ if ( item.userData )
+ {
+ delete item.userData;
+ }
+
+ m_items.Remove( index );
+
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * clears the listbox, deleting all panels and userData
+ */
+void BuyPresetListBox::DeleteAllItems()
+{
+ while ( m_items.Count() )
+ {
+ RemoveItem( 0 );
+ }
+
+ // move the scrollbar to the top of the list
+ m_vbar->SetValue(0);
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Handles Count changes
+ */
+void BuyPresetListBox::OnSizeChanged(int wide, int tall)
+{
+ BaseClass::OnSizeChanged(wide, tall);
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Positions listbox items, etc after internal changes
+ */
+void BuyPresetListBox::PerformLayout()
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ int vpixels = computeVPixelsNeeded();
+
+ int visibleIndex = m_visibleIndex;
+
+ //!! need to make it recalculate scroll positions
+ m_vbar->SetVisible(true);
+ m_vbar->SetEnabled(false);
+ m_vbar->SetRange( 0, (MAX( 0, vpixels - tall + m_iDefaultHeight )) );
+ m_vbar->SetRangeWindow( m_iDefaultHeight );
+ m_vbar->SetButtonPressedScrollValue( m_iDefaultHeight ); // standard height of labels/buttons etc.
+ m_vbar->SetPos(wide - m_iScrollbarSize, 1);
+ m_vbar->SetSize(m_iScrollbarSize, tall - 2);
+
+ m_visibleIndex = visibleIndex;
+
+ int top = MAX( 0, m_vbar->GetValue() );
+
+ m_pPanelEmbedded->SetPos( 1, -top );
+ m_pPanelEmbedded->SetSize( wide-m_iScrollbarSize -2, vpixels );
+
+ // Now lay out the controls on the embedded panel
+ int y = 0;
+ int h = 0;
+ int totalh = 0;
+
+ int i;
+ for ( i = 0; i < m_items.Count(); i++, y += h )
+ {
+ // add in a little buffer between panels
+ y += m_iPanelBuffer;
+ DataItem item = m_items[i];
+
+ h = item.panel->GetTall();
+
+ totalh += h;
+ item.panel->SetBounds( 8, y, wide - m_iScrollbarSize - 8 - 8, h );
+ item.panel->InvalidateLayout();
+ }
+
+ if ( m_visibleIndex >= 0 && m_visibleIndex < m_items.Count() )
+ {
+
+ int vpos = 0;
+
+ int tempWide, tempTall;
+ GetSize( tempWide, tempTall );
+
+ int vtop, vbottom;
+ m_vbar->GetRange( vtop, vbottom );
+
+ int tempTop = MAX( 0, m_vbar->GetValue() ); // top pixel in the embedded panel
+ int bottom = tempTop + tempTall - 2;
+
+ int itemTop, itemLeft, itemBottom, itemRight;
+ m_items[m_visibleIndex].panel->GetBounds( itemLeft, itemTop, itemRight, itemBottom );
+ itemBottom += itemTop;
+ itemRight += itemLeft;
+
+ if ( itemTop < tempTop )
+ {
+ // item's top is too high
+ vpos -= ( tempTop - itemTop );
+
+ m_vbar->SetValue(vpos);
+ OnSliderMoved(vpos);
+ }
+ else if ( itemBottom > bottom )
+ {
+ // item's bottom is too low
+ vpos += ( itemBottom - bottom );
+
+ m_vbar->SetValue(vpos);
+ OnSliderMoved(vpos);
+ }
+ }
+
+ if ( m_lastSize == vpixels )
+ {
+ m_visibleIndex = -1;
+ }
+ m_lastSize = vpixels;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Try to ensure that the given index is visible
+ */
+void BuyPresetListBox::MakeItemVisible( int index )
+{
+ m_visibleIndex = index;
+ m_lastSize = 0;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Loads colors, fonts, etc
+ */
+void BuyPresetListBox::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ SetBgColor(GetSchemeColor("BuyPresetListBox.BgColor", GetBgColor(), pScheme));
+
+ SetBorder(pScheme->GetBorder("BrowserBorder"));
+ m_vbar->SetBorder(pScheme->GetBorder("BrowserBorder"));
+
+ PerformLayout();
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Handles slider being dragged
+ */
+void BuyPresetListBox::OnSliderMoved( int position )
+{
+ InvalidateLayout();
+ Repaint();
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Moves slider to the top
+ */
+void BuyPresetListBox::MoveScrollBarToTop()
+{
+ m_vbar->SetValue(0);
+ OnSliderMoved(0);
+}
+
diff --git a/game/client/cstrike/VGUI/buypreset_listbox.h b/game/client/cstrike/VGUI/buypreset_listbox.h
new file mode 100644
index 0000000..68d6de6
--- /dev/null
+++ b/game/client/cstrike/VGUI/buypreset_listbox.h
@@ -0,0 +1,78 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef BUYPRESET_LISTBOX_H
+#define BUYPRESET_LISTBOX_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui_controls/Panel.h>
+
+#include <utlvector.h>
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * ListBox-style control with behavior needed by weapon lists for BuyPreset editing
+ */
+class BuyPresetListBox : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( BuyPresetListBox, vgui::Panel );
+
+public:
+ BuyPresetListBox( vgui::Panel *parent, char const *panelName );
+ ~BuyPresetListBox();
+
+ virtual int AddItem( vgui::Panel *panel, void * userData ); ///< Adds an item to the end of the listbox. UserData is assumed to be a pointer that can be freed by the listbox if non-NULL.
+ virtual int GetItemCount( void ) const; ///< Returns the number of items in the listbox
+ void SwapItems( int index1, int index2 ); ///< Exchanges two items in the listbox
+ void MakeItemVisible( int index ); ///< Try to ensure that the given index is visible
+
+ vgui::Panel * GetItemPanel( int index ) const; ///< Returns the panel in the given index, or NULL
+ void * GetItemUserData( int index ); ///< Returns the userData in the given index, or NULL
+ void SetItemUserData( int index, void * userData ); ///< Sets the userData in the given index
+
+ virtual void RemoveItem( int index ); ///< Removes an item from the table (changing the indices of all following items), deleting the panel and userData
+ virtual void DeleteAllItems(); ///< clears the listbox, deleting all panels and userData
+
+ // overrides
+ virtual void OnSizeChanged(int wide, int tall); ////< Handles size changes
+ MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position ); ///< Handles slider being dragged
+ virtual void OnMouseWheeled(int delta); ///< Scrolls the list according to the mouse wheel movement
+ virtual void MoveScrollBarToTop(); ///< Moves slider to the top
+
+protected:
+
+ virtual int computeVPixelsNeeded( void ); ///< Computes vertical pixels needed by listbox contents
+
+ virtual void PerformLayout(); ///< Positions listbox items, etc after internal changes
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); ///< Loads colors, fonts, etc
+
+ virtual void OnCommand( const char *command ); ///< Passes commands up to the parent
+
+private:
+ enum { SCROLLBAR_SIZE = 18, DEFAULT_HEIGHT = 24, PANELBUFFER = 5 };
+
+ typedef struct dataitem_s
+ {
+ vgui::Panel *panel;
+ void * userData;
+ } DataItem;
+ CUtlVector< DataItem > m_items;
+
+ vgui::ScrollBar *m_vbar;
+ vgui::Panel *m_pPanelEmbedded;
+
+ int m_iScrollbarSize;
+ int m_iDefaultHeight;
+ int m_iPanelBuffer;
+
+ int m_visibleIndex;
+ int m_lastSize;
+};
+
+#endif // BUYPRESET_LISTBOX_H
diff --git a/game/client/cstrike/VGUI/buypreset_panel.cpp b/game/client/cstrike/VGUI/buypreset_panel.cpp
new file mode 100644
index 0000000..321984b
--- /dev/null
+++ b/game/client/cstrike/VGUI/buypreset_panel.cpp
@@ -0,0 +1,447 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#include "weapon_csbase.h"
+#include "cs_ammodef.h"
+
+#include <vgui/IVGui.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/Label.h>
+#include <vgui/ILocalize.h>
+#include "vgui_controls/BuildGroup.h"
+#include "vgui_controls/BitmapImagePanel.h"
+#include "vgui_controls/TextEntry.h"
+#include "vgui_controls/TextImage.h"
+#include "vgui_controls/RichText.h"
+#include "vgui_controls/QueryBox.h"
+#include "career_box.h"
+#include "buypreset_listbox.h"
+#include "buypreset_weaponsetlabel.h"
+#include "backgroundpanel.h"
+
+#include "cstrike/bot/shared_util.h"
+
+using namespace vgui;
+
+const float horizTitleRatio = 18.0f/68.0f;
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+/*
+class PresetNameTextEntry : public TextEntry
+{
+public:
+ PresetNameTextEntry(Panel *parent, CBuyPresetEditMainMenu *menu, const char *name ) : TextEntry( parent, name )
+ {
+ m_pMenu = menu;
+ }
+
+ virtual void FireActionSignal()
+ {
+ TextEntry::FireActionSignal();
+ if ( m_pMenu )
+ {
+ m_pMenu->SetDirty();
+ }
+ }
+
+private:
+ CBuyPresetEditMainMenu *m_pMenu;
+};
+*/
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+int GetScaledValue( HScheme hScheme, int unscaled )
+{
+ int val = scheme()->GetProportionalScaledValueEx( hScheme, unscaled );
+ return GetAlternateProportionalValueFromScaled( hScheme, val );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+class PresetBackgroundPanel : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+
+public:
+ PresetBackgroundPanel( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
+ {
+ };
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetBorder( pScheme->GetBorder("ButtonBorder") );
+ m_lineColor = pScheme->GetColor( "Border.Bright", Color( 0, 0, 0, 0 ) );
+ }
+
+ virtual void ApplySettings( KeyValues *inResourceData )
+ {
+ BaseClass::ApplySettings( inResourceData );
+
+ m_lines.RemoveAll();
+ KeyValues *lines = inResourceData->FindKey( "lines", false );
+ if ( lines )
+ {
+ KeyValues *line = lines->GetFirstValue();
+ while ( line )
+ {
+ const char *str = line->GetString( NULL, "" );
+ Vector4D p;
+ int numPoints = sscanf( str, "%f %f %f %f", &p[0], &p[1], &p[2], &p[3] );
+ if ( numPoints == 4 )
+ {
+ m_lines.AddToTail( p );
+ }
+ line = line->GetNextValue();
+ }
+ }
+ }
+
+ virtual void PaintBackground( void )
+ {
+ BaseClass::PaintBackground();
+
+ vgui::surface()->DrawSetColor( m_lineColor );
+ vgui::surface()->DrawSetTextColor( m_lineColor );
+ for ( int i=0; i<m_scaledLines.Count(); ++i )
+ {
+ int x1, x2, y1, y2;
+
+ x1 = m_scaledLines[i][0];
+ y1 = m_scaledLines[i][1];
+ x2 = m_scaledLines[i][2];
+ y2 = m_scaledLines[i][3];
+
+ vgui::surface()->DrawFilledRect( x1, y1, x2, y2 );
+ }
+ }
+
+ virtual void PerformLayout( void )
+ {
+ m_scaledLines.RemoveAll();
+ for ( int i=0; i<m_lines.Count(); ++i )
+ {
+ int x1, x2, y1, y2;
+
+ x1 = GetScaledValue( GetScheme(), m_lines[i][0] );
+ y1 = GetScaledValue( GetScheme(), m_lines[i][1] );
+ x2 = GetScaledValue( GetScheme(), m_lines[i][2] );
+ y2 = GetScaledValue( GetScheme(), m_lines[i][3] );
+
+ if ( x1 == x2 )
+ {
+ ++x2;
+ }
+
+ if ( y1 == y2 )
+ {
+ ++y2;
+ }
+
+ m_scaledLines.AddToTail( Vector4D( x1, y1, x2, y2 ) );
+ }
+ }
+
+private:
+ Color m_lineColor;
+ CUtlVector< Vector4D > m_lines;
+ CUtlVector< Vector4D > m_scaledLines;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+BuyPresetEditPanel::BuyPresetEditPanel( Panel *parent, const char *panelName, const char *resourceFilename, int fallbackIndex, bool editableName ) : BaseClass( parent, panelName )
+{
+ SetProportional( parent->IsProportional() );
+ if ( IsProportional() )
+ {
+ m_baseWide = m_baseTall = scheme()->GetProportionalScaledValueEx( GetScheme(), 100 );
+ }
+ else
+ {
+ m_baseWide = m_baseTall = 100;
+ }
+ SetSize( m_baseWide, m_baseTall );
+
+ m_fallbackIndex = fallbackIndex;
+
+ m_pBgPanel = new PresetBackgroundPanel( this, "mainBackground" );
+
+ m_pTitleEntry = NULL;
+ m_pTitleLabel = NULL;
+ m_pCostLabel = NULL;
+ /*
+ m_pTitleEntry = new PresetNameTextEntry( this, dynamic_cast<CBuyPresetEditMainMenu *>(parent), "titleEntry" );
+ m_pTitleLabel = new Label( this, "title", "" );
+ m_pCostLabel = new Label( this, "cost", "" );
+ */
+
+ m_pPrimaryWeapon = new WeaponLabel( this, "primary" );
+ m_pSecondaryWeapon = new WeaponLabel( this, "secondary" );
+
+ m_pHEGrenade = new EquipmentLabel( this, "hegrenade" );
+ m_pSmokeGrenade = new EquipmentLabel( this, "smokegrenade" );
+ m_pFlashbangs = new EquipmentLabel( this, "flashbang" );
+
+ m_pDefuser = new EquipmentLabel( this, "defuser" );
+ m_pNightvision = new EquipmentLabel( this, "nightvision" );
+
+ m_pArmor = new EquipmentLabel( this, "armor" );
+
+ if ( resourceFilename )
+ {
+ LoadControlSettings( resourceFilename );
+ }
+
+ int x, y, w, h;
+ m_pBgPanel->GetBounds( x, y, w, h );
+
+ m_baseWide = x + w;
+ m_baseTall = y + h;
+ SetSize( m_baseWide, m_baseTall );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+BuyPresetEditPanel::~BuyPresetEditPanel()
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void BuyPresetEditPanel::SetWeaponSet( const WeaponSet *pWeaponSet, bool current )
+{
+ // set to empty state
+ Reset();
+
+ // now fill in items
+ if ( pWeaponSet )
+ {
+ if ( m_pTitleLabel )
+ {
+ m_pTitleLabel->SetText( SharedVarArgs( "#Cstrike_BuyPresetChoice%d", m_fallbackIndex ) );
+ }
+ if ( m_pTitleEntry )
+ {
+ m_pTitleEntry->SetText( SharedVarArgs( "#Cstrike_BuyPresetChoice%d", m_fallbackIndex ) );
+ }
+
+ if ( m_pCostLabel )
+ {
+ const int BufLen = 256;
+ wchar_t wbuf[BufLen];
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( pWeaponSet->FullCost() ) );
+ m_pCostLabel->SetText( wbuf );
+ }
+
+ m_pPrimaryWeapon->SetWeapon( &pWeaponSet->m_primaryWeapon, true, true );
+ m_pSecondaryWeapon->SetWeapon( &pWeaponSet->m_secondaryWeapon, false, true );
+
+ if ( pWeaponSet->m_HEGrenade )
+ m_pHEGrenade->SetItem( "gfx/vgui/hegrenade_square", 1 );
+ if ( pWeaponSet->m_smokeGrenade )
+ m_pSmokeGrenade->SetItem( "gfx/vgui/smokegrenade_square", 1 );
+ if ( pWeaponSet->m_flashbangs )
+ m_pFlashbangs->SetItem( "gfx/vgui/flashbang_square", pWeaponSet->m_flashbangs );
+
+ if ( pWeaponSet->m_defuser )
+ m_pDefuser->SetItem( "gfx/vgui/defuser", 1 );
+ if ( pWeaponSet->m_nightvision )
+ m_pNightvision->SetItem( "gfx/vgui/nightvision", 1 );
+
+ if ( pWeaponSet->m_armor )
+ {
+ if ( pWeaponSet->m_helmet )
+ m_pArmor->SetItem( "gfx/vgui/kevlar_helmet", 1 );
+ else
+ m_pArmor->SetItem( "gfx/vgui/kevlar", 1 );
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void BuyPresetEditPanel::SetText( const wchar_t *text )
+{
+ if ( !text )
+ text = L"";
+ if ( m_pTitleLabel )
+ {
+ m_pTitleLabel->SetText( text );
+ }
+ if ( m_pTitleEntry )
+ {
+ m_pTitleEntry->SetText( text );
+ }
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Handle command callbacks
+ */
+void BuyPresetEditPanel::OnCommand( const char *command )
+{
+ if (stricmp(command, "close"))
+ {
+ PostActionSignal( new KeyValues("Command", "command", SharedVarArgs( "%s %d", command, m_fallbackIndex )) );
+ }
+
+ BaseClass::OnCommand(command);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void BuyPresetEditPanel::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetBgColor( Color( 0, 0, 0, 0 ) );
+
+ IBorder *pBorder = NULL;
+
+ int i;
+
+ for (i = 0; i < GetChildCount(); i++)
+ {
+ // perform auto-layout on the child panel
+ Panel *child = GetChild(i);
+ if (!child)
+ continue;
+
+ if ( !stricmp( "button", child->GetClassName() ) )
+ {
+ Button *pButton = dynamic_cast<Button *>(child);
+ if ( pButton )
+ {
+ pButton->SetDefaultBorder( pBorder );
+ pButton->SetDepressedBorder( pBorder );
+ pButton->SetKeyFocusBorder( pBorder );
+ }
+ }
+ }
+
+ pBorder = pScheme->GetBorder("BuyPresetButtonBorder");
+
+ const int NumButtons = 4;
+ const char * buttonNames[4] = { "editPrimary", "editSecondary", "editGrenades", "editEquipment" };
+ for ( i=0; i<NumButtons; ++i )
+ {
+ Panel *pPanel = FindChildByName( buttonNames[i] );
+ if ( pPanel )
+ {
+ pPanel->SetBorder( pBorder );
+ if ( !stricmp( "button", pPanel->GetClassName() ) )
+ {
+ Button *pButton = dynamic_cast<Button *>(pPanel);
+ if ( pButton )
+ {
+ pButton->SetDefaultBorder( pBorder );
+ pButton->SetDepressedBorder( pBorder );
+ pButton->SetKeyFocusBorder( pBorder );
+
+ Color fgColor, bgColor;
+ fgColor = GetSchemeColor("Label.TextDullColor", GetFgColor(), pScheme);
+ bgColor = Color( 0, 0, 0, 0 );
+ pButton->SetDefaultColor( fgColor, bgColor );
+ }
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Overrides EditablePanel's resizing of children to scale them proportionally to the main panel's change.
+ */
+void BuyPresetEditPanel::OnSizeChanged( int wide, int tall )
+{
+ if ( !m_baseWide )
+ m_baseWide = 1;
+ if ( !m_baseTall )
+ m_baseTall = 1;
+
+ Panel::OnSizeChanged(wide, tall);
+ InvalidateLayout();
+
+ if ( wide == m_baseWide && tall == m_baseTall )
+ {
+ Repaint();
+ return;
+ }
+
+ float xScale = wide / (float) m_baseWide;
+ float yScale = tall / (float) m_baseTall;
+
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ // perform auto-layout on the child panel
+ Panel *child = GetChild(i);
+ if (!child)
+ continue;
+
+ int x, y, w, t;
+ child->GetBounds(x, y, w, t);
+
+ int newX = (int) x * xScale;
+ int newY = (int) y * yScale;
+ int newW = (int) (x+w) * xScale - newX;
+ int newT = (int) t * yScale;
+
+ // make sure the child isn't too big...
+ if(newX+newW>wide)
+ {
+ continue;
+ }
+
+ if(newY+newT>tall)
+ {
+ continue;
+ }
+
+ child->SetBounds(newX, newY, newW, newT);
+ child->InvalidateLayout();
+ }
+ Repaint();
+
+ // update the baselines
+ m_baseWide = wide;
+ m_baseTall = tall;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void BuyPresetEditPanel::Reset()
+{
+ if ( m_pTitleLabel )
+ {
+ m_pTitleLabel->SetText( "#Cstrike_BuyPresetNewChoice" );
+ }
+ if ( m_pTitleEntry )
+ {
+ m_pTitleEntry->SetText( "#Cstrike_BuyPresetNewChoice" );
+ }
+ if ( m_pCostLabel )
+ {
+ m_pCostLabel->SetText( "" );
+ }
+
+ BuyPresetWeapon weapon;
+ m_pPrimaryWeapon->SetWeapon( &weapon, true, false );
+ m_pSecondaryWeapon->SetWeapon( &weapon, false, false );
+
+ m_pHEGrenade->SetItem( NULL, 1 );
+ m_pSmokeGrenade->SetItem( NULL, 1 );
+ m_pFlashbangs->SetItem( NULL, 1 );
+
+ m_pDefuser->SetItem( NULL, 1 );
+ m_pNightvision->SetItem( NULL, 1 );
+
+ m_pArmor->SetItem( NULL, 1 );
+}
+
+//--------------------------------------------------------------------------------------------------------------
diff --git a/game/client/cstrike/VGUI/buypreset_weaponsetlabel.h b/game/client/cstrike/VGUI/buypreset_weaponsetlabel.h
new file mode 100644
index 0000000..9c205ad
--- /dev/null
+++ b/game/client/cstrike/VGUI/buypreset_weaponsetlabel.h
@@ -0,0 +1,302 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef BUYPRESET_WEAPONSETLABEL_H
+#define BUYPRESET_WEAPONSETLABEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui_controls/Panel.h>
+#include <vgui/IImage.h>
+
+namespace vgui
+{
+ class TextImage;
+ class TextEntry;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/// Helper function: draws a simple dashed line
+void DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen);
+
+//--------------------------------------------------------------------------------------------------------------
+// Purpose: Wraps an IImage to perform resizes properly
+class BuyPresetImage : public vgui::IImage
+{
+public:
+ BuyPresetImage( vgui::IImage *realImage )
+ {
+ m_image = realImage;
+ if ( m_image )
+ {
+ m_image->GetSize( m_wide, m_tall );
+ }
+ else
+ {
+ m_wide = m_tall = 0;
+ }
+ }
+
+ // Call to Paint the image
+ // Image will draw within the current panel context at the specified position
+ virtual void Paint()
+ {
+ if ( !m_image )
+ return;
+
+ m_image->Paint();
+ }
+
+ // Set the position of the image
+ virtual void SetPos(int x, int y)
+ {
+ if ( !m_image )
+ return;
+
+ m_image->SetPos( x, y );
+ }
+
+ // Gets the size of the content
+ virtual void GetContentSize(int &wide, int &tall)
+ {
+ if ( !m_image )
+ return;
+
+ m_image->GetSize( wide, tall );
+ }
+
+ // Get the size the image will actually draw in (usually defaults to the content size)
+ virtual void GetSize(int &wide, int &tall)
+ {
+ if ( !m_image )
+ {
+ wide = tall = 0;
+ return;
+ }
+
+ wide = m_wide;
+ tall = m_tall;
+ }
+
+ // Sets the size of the image
+ virtual void SetSize(int wide, int tall)
+ {
+ m_wide = wide;
+ m_tall = tall;
+ if ( !m_image )
+ return;
+
+ m_image->SetSize( wide, tall );
+ }
+
+ // Set the draw color
+ virtual void SetColor(Color col)
+ {
+ if ( !m_image )
+ return;
+
+ m_image->SetColor( col );
+ }
+
+ virtual bool Evict()
+ {
+ return false;
+ }
+
+ virtual int GetNumFrames()
+ {
+ return 0;
+ }
+
+ virtual void SetFrame( int nFrame )
+ {
+ }
+
+ virtual vgui::HTexture GetID()
+ {
+ return 0;
+ }
+
+ virtual void SetRotation( int iRotation )
+ {
+ return;
+ }
+
+private:
+ vgui::IImage *m_image;
+ int m_wide, m_tall;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+struct ImageInfo {
+ vgui::IImage *image;
+ int w;
+ int h;
+ int x;
+ int y;
+ int fullW;
+ int fullH;
+
+ void FitInBounds( int baseX, int baseY, int width, int height, bool center, int scaleAt1024, bool halfHeight = false );
+ void Paint();
+};
+
+//--------------------------------------------------------------------------------------------------------------
+class WeaponImageInfo
+{
+public:
+ WeaponImageInfo();
+ ~WeaponImageInfo();
+
+ void SetBounds( int left, int top, int wide, int tall );
+ void SetCentered( bool isCentered );
+ void SetScaleAt1024( int weaponScale, int ammoScale );
+ void SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool useCurrentAmmoType );
+
+ void ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional );
+
+ void Paint();
+ void PaintText();
+
+private:
+ void PerformLayout();
+
+ int m_left;
+ int m_top;
+ int m_wide;
+ int m_tall;
+
+ bool m_isPrimary;
+
+ int m_weaponScale;
+ int m_ammoScale;
+
+ bool m_needLayout;
+ bool m_isCentered;
+ ImageInfo m_weapon;
+ ImageInfo m_ammo;
+
+ vgui::TextImage *m_pAmmoText;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+class ItemImageInfo
+{
+public:
+ ItemImageInfo();
+ ~ItemImageInfo();
+
+ void SetBounds( int left, int top, int wide, int tall );
+ void SetItem( const char *imageFname, int count );
+ void ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional );
+
+ void Paint();
+ void PaintText();
+
+private:
+ void PerformLayout();
+
+ int m_left;
+ int m_top;
+ int m_wide;
+ int m_tall;
+
+ int m_count;
+
+ bool m_needLayout;
+ ImageInfo m_image;
+
+ vgui::TextImage *m_pText;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+class WeaponLabel : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+public:
+ WeaponLabel(vgui::Panel *parent, const char *panelName);
+ ~WeaponLabel();
+
+ void SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool showAmmo = false );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ virtual void PerformLayout();
+ virtual void Paint();
+
+protected:
+ WeaponImageInfo m_weapon;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+class EquipmentLabel : public vgui::Panel
+{
+ typedef vgui::Panel BaseClass;
+public:
+ EquipmentLabel(vgui::Panel *parent, const char *panelName, const char *imageFname = NULL);
+ ~EquipmentLabel();
+
+ void SetItem( const char *imageFname, int count );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ virtual void PerformLayout();
+ virtual void Paint();
+
+protected:
+ ItemImageInfo m_item;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * BuyPresetEditPanel is a panel displaying a graphical representation of a buy preset.
+ */
+class BuyPresetEditPanel : public vgui::EditablePanel
+{
+ typedef vgui::EditablePanel BaseClass;
+public:
+ BuyPresetEditPanel( vgui::Panel *parent, const char *panelName, const char *resourceFilename, int fallbackIndex, bool editableName );
+ virtual ~BuyPresetEditPanel();
+
+ void SetWeaponSet( const WeaponSet *pWeaponSet, bool current );
+ virtual void SetText( const wchar_t *text );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ void OnCommand( const char *command); ///< Handle command callbacks
+
+ virtual void OnSizeChanged( int wide, int tall );
+
+ void SetPanelBgColor( Color color ) { if (m_pBgPanel) m_pBgPanel->SetBgColor( color ); }
+
+protected:
+ void Reset();
+
+ vgui::Panel *m_pBgPanel;
+
+ vgui::TextEntry *m_pTitleEntry;
+ vgui::Label *m_pTitleLabel;
+ vgui::Label *m_pCostLabel;
+
+ WeaponLabel *m_pPrimaryWeapon;
+ WeaponLabel *m_pSecondaryWeapon;
+
+ EquipmentLabel *m_pHEGrenade;
+ EquipmentLabel *m_pSmokeGrenade;
+ EquipmentLabel *m_pFlashbangs;
+
+ EquipmentLabel *m_pDefuser;
+ EquipmentLabel *m_pNightvision;
+
+ EquipmentLabel *m_pArmor;
+
+ int m_baseWide;
+ int m_baseTall;
+
+ int m_fallbackIndex;
+};
+
+
+#endif // BUYPRESET_WEAPONSETLABEL_H
diff --git a/game/client/cstrike/VGUI/career_box.cpp b/game/client/cstrike/VGUI/career_box.cpp
new file mode 100644
index 0000000..308a44b
--- /dev/null
+++ b/game/client/cstrike/VGUI/career_box.cpp
@@ -0,0 +1,1296 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+// Author: Matthew D. Campbell ([email protected]), 2003
+
+#include "cbase.h"
+
+#include <vgui/KeyCode.h>
+#include "career_box.h"
+#include "career_button.h"
+#include "buypreset_listbox.h"
+#include <vgui_controls/TextImage.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/ComboBox.h>
+#include "cs_ammodef.h"
+#include "weapon_csbase.h"
+#include "backgroundpanel.h"
+#include "cs_gamerules.h"
+
+#include <vgui/IInput.h>
+#include "bot/shared_util.h"
+#include <vgui_controls/BitmapImagePanel.h>
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+using namespace vgui;
+
+//--------------------------------------------------------------------------------------------------------------
+class ConVarToggleCheckButton : public vgui::CheckButton
+{
+ DECLARE_CLASS_SIMPLE( ConVarToggleCheckButton, vgui::CheckButton );
+
+public:
+ ConVarToggleCheckButton( vgui::Panel *parent, const char *panelName, const char *text );
+ ~ConVarToggleCheckButton();
+
+ virtual void SetSelected( bool state );
+
+ virtual void Paint();
+
+ void Reset();
+ void ApplyChanges();
+ bool HasBeenModified();
+ void SetConVar( const char *name );
+
+ virtual void ApplySettings( KeyValues *inResourceData )
+ {
+ BaseClass::ApplySettings( inResourceData );
+
+ const char *name = inResourceData->GetString( "convar", NULL );
+ if ( name )
+ {
+ SetConVar( name );
+ }
+ }
+
+private:
+ MESSAGE_FUNC( OnButtonChecked, "CheckButtonChecked" );
+
+ char *m_pszCvarName;
+ bool m_bStartValue;
+};
+
+
+//--------------------------------------------------------------------------------------------------------------
+ConVarToggleCheckButton::ConVarToggleCheckButton( Panel *parent, const char *panelName, const char *text )
+ : CheckButton( parent, panelName, text )
+{
+ m_pszCvarName = NULL;
+ AddActionSignalTarget( this );
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+ConVarToggleCheckButton::~ConVarToggleCheckButton()
+{
+ if ( m_pszCvarName )
+ delete[] m_pszCvarName;
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::SetConVar( const char *name )
+{
+ if ( m_pszCvarName )
+ delete[] m_pszCvarName;
+
+ m_pszCvarName = CloneString( name );
+
+ if (m_pszCvarName && *m_pszCvarName)
+ {
+ Reset();
+ }
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::Paint()
+{
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ {
+ BaseClass::Paint();
+ return;
+ }
+
+ // Look up current value
+ ConVar const *var = cvar->FindVar( m_pszCvarName );
+ if ( !var )
+ return;
+ bool value = var->GetBool();
+
+ if (value != m_bStartValue)
+ {
+ SetSelected( value );
+ m_bStartValue = value;
+ }
+ BaseClass::Paint();
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::ApplyChanges()
+{
+ m_bStartValue = IsSelected();
+ ConVar *var = (ConVar *)cvar->FindVar( m_pszCvarName );
+ if ( !var )
+ return;
+ var->SetValue(m_bStartValue);
+
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::Reset()
+{
+ ConVar const *var = cvar->FindVar( m_pszCvarName );
+ if ( !var )
+ return;
+ m_bStartValue = var->GetBool();
+ SetSelected(m_bStartValue);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+bool ConVarToggleCheckButton::HasBeenModified()
+{
+ return IsSelected() != m_bStartValue;
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::SetSelected( bool state )
+{
+ BaseClass::SetSelected( state );
+
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ return;
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void ConVarToggleCheckButton::OnButtonChecked()
+{
+ if (HasBeenModified())
+ {
+ PostActionSignal(new KeyValues("ControlModified"));
+ }
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+CCareerBaseBox::CCareerBaseBox(Panel *parent, const char *panelName, bool loadResources, bool useCareerButtons) : Frame(parent, panelName, false)
+{
+// @TODO: SetScheme("CareerBoxScheme");
+ SetScheme("ClientScheme");
+ SetProportional( true );
+ SetMoveable(false);
+ SetSizeable(false);
+
+ m_bgColor = Color( 0, 0, 0, 0 );
+ m_borderColor = Color( 0, 0, 0, 0 );
+
+ m_pTextLabel = new Label( this, "TextLabel", "" );
+
+ if ( useCareerButtons )
+ {
+ m_pOkButton = new CCareerButton( this, "OkButton", "", "", false );
+ m_pCancelButton = new CCareerButton( this, "CancelButton", "", "", false );
+ }
+ else
+ {
+ m_pOkButton = new Button( this, "OkButton", "" );
+ m_pCancelButton = new Button( this, "CancelButton", "" );
+ }
+ m_pOkButton->SetVisible(false);
+ if ( useCareerButtons )
+ {
+ m_buttons.PutElement( m_pOkButton );
+ m_buttons.PutElement( m_pCancelButton );
+ }
+ m_cancelFocus = false;
+
+ if (loadResources)
+ {
+ const int BufLen = strlen(panelName) + 32;
+ char *buf = new char[BufLen];
+ Q_snprintf( buf, BufLen, "Resource/Career/%s.res", panelName );
+ LoadControlSettings( buf );
+ delete[] buf;
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+vgui::Panel * CCareerBaseBox::CreateControlByName(const char *controlName)
+{
+ if ( Q_stricmp( controlName, "ConVarCheckButton" ) == 0 )
+ {
+ ConVarToggleCheckButton *button = new ConVarToggleCheckButton( NULL, controlName, "" );
+ m_conVarCheckButtons.PutElement( button );
+ return button;
+ }
+
+ return BaseClass::CreateControlByName( controlName );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::SetCancelButtonAsDefault()
+{
+ m_cancelFocus = true;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::SetLabelText( const wchar_t *text )
+{
+ m_pTextLabel->SetText(text);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::SetLabelText( const char *text )
+{
+ m_pTextLabel->SetText(text);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ for (int i=0; i<m_buttons.GetCount(); ++i)
+ {
+ m_buttons[i]->SetArmedSound("UI/buttonrollover.wav");
+ m_buttons[i]->SetDepressedSound("UI/buttonclick.wav");
+ m_buttons[i]->SetReleasedSound("UI/buttonclickrelease.wav");
+ }
+
+ m_bgColor = GetSchemeColor("Popup.BgColor", Color( 64, 64, 64, 255 ), pScheme);
+ m_borderColor = GetSchemeColor("FgColor", Color( 64, 64, 64, 255 ), pScheme);
+
+ SetBorder( pScheme->GetBorder( "BaseBorder" ) );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::PerformLayout( )
+{
+ BaseClass::PerformLayout();
+
+ int x, y, w, h;
+ GetBounds(x, y, w, h);
+
+ int screenWide, screenTall;
+ GetHudSize( screenWide, screenTall );
+ if ( x + w/2 != screenWide/2 )
+ {
+ SetPos( screenWide/2 - w/2, screenTall/2 - h/2 );
+ GetBounds(x, y, w, h);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::PaintBackground( )
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ DrawRoundedBackground( m_bgColor, wide, tall );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::PaintBorder( )
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ DrawRoundedBorder( m_borderColor, wide, tall );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::ShowWindow()
+{
+ SetVisible( true );
+ SetEnabled( true );
+ MoveToFront();
+
+ if ( m_pCancelButton->IsVisible() && m_cancelFocus )
+ {
+ m_pCancelButton->RequestFocus();
+ }
+ else if ( m_pOkButton->IsVisible() )
+ {
+ m_pOkButton->RequestFocus();
+ }
+ else // handle message boxes with no button
+ {
+ RequestFocus();
+ }
+
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::DoModal()
+{
+ ShowWindow();
+ input()->SetAppModalSurface(GetVPanel());
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::OnKeyCodeTyped(KeyCode code)
+{
+ if (code == KEY_ESCAPE)
+ {
+ OnCommand("Cancel");
+ }
+ else if (code == KEY_ENTER)
+ {
+ BaseClass::OnKeyCodeTyped( KEY_SPACE );
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::OnCommand(const char *command)
+{
+ KeyValues *okSettings = new KeyValues( "GetCommand" );
+ if ( m_pOkButton->RequestInfo( okSettings ) )
+ {
+ const char *okCommand = okSettings->GetString( "command", "Ok" );
+ if ( stricmp(command, okCommand) == 0 )
+ {
+ for (int i=0; i<m_conVarCheckButtons.GetCount(); ++i)
+ {
+ m_conVarCheckButtons[i]->ApplyChanges();
+ }
+ }
+ }
+
+ if (stricmp(command, "close"))
+ {
+ PostActionSignal( new KeyValues("Command", "command", command) );
+ }
+
+ BaseClass::OnCommand(command);
+
+ Close();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerBaseBox::AddButton( vgui::Button *pButton )
+{
+ m_buttons.PutElement( pButton );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CCareerQueryBox::CCareerQueryBox(vgui::Panel *parent, const char *panelName, const char *resourceName) : CCareerBaseBox(parent, panelName, (resourceName == NULL))
+{
+ if ( resourceName )
+ {
+ LoadControlSettings( resourceName );
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CCareerQueryBox::CCareerQueryBox(const char *title, const char *labelText, const char *panelName, vgui::Panel *parent) : CCareerBaseBox(parent, panelName)
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CCareerQueryBox::CCareerQueryBox(const wchar_t *title, const wchar_t *labelText, const char *panelName, vgui::Panel *parent) : CCareerBaseBox(parent, panelName)
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CCareerQueryBox::~CCareerQueryBox()
+{
+}
+
+// sorted order weapon list -----------------------------------------------------------------------
+const int NUM_SECONDARY_WEAPONS = 7;
+static CSWeaponID s_secondaryWeapons[NUM_SECONDARY_WEAPONS] =
+{
+ WEAPON_NONE,
+ WEAPON_USP,
+ WEAPON_GLOCK,
+ WEAPON_DEAGLE,
+ WEAPON_ELITE,
+ WEAPON_P228,
+ WEAPON_FIVESEVEN,
+};
+
+const int NUM_PRIMARY_WEAPONS = 23;
+static CSWeaponID s_primaryWeapons[NUM_PRIMARY_WEAPONS] =
+{
+ WEAPON_NONE,
+
+ // Assault Rifles
+ CSWeaponID(-WEAPONTYPE_RIFLE),
+ WEAPON_SG552,
+ WEAPON_AUG,
+ WEAPON_AK47,
+ WEAPON_M4A1,
+ WEAPON_GALIL,
+ WEAPON_FAMAS,
+
+ // Snipers
+ CSWeaponID(-WEAPONTYPE_SNIPER_RIFLE),
+ WEAPON_AWP,
+ WEAPON_SG550,
+ WEAPON_G3SG1,
+ WEAPON_SCOUT,
+
+ // SMG
+ CSWeaponID(-WEAPONTYPE_SUBMACHINEGUN),
+ WEAPON_P90,
+ WEAPON_UMP45,
+ WEAPON_MP5NAVY,
+ WEAPON_MAC10,
+ WEAPON_TMP,
+
+ // Heavy
+ CSWeaponID(-WEAPONTYPE_SHOTGUN),
+ WEAPON_M249,
+ WEAPON_XM1014,
+ WEAPON_M3,
+// WEAPON_SHIELDGUN,
+};
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+class CWeaponButton : public vgui::Button
+{
+ typedef vgui::Button BaseClass;
+
+public:
+ CWeaponButton( BuyPresetListBox *pParent, CSWeaponID weaponID, bool isPrimary ) : BaseClass( pParent->GetParent(), SharedVarArgs( "WeaponButton%d", weaponID ), "" )
+ {
+ m_isPrimary = isPrimary;
+ m_pImage = NULL;
+ m_pTitleImage = new TextImage( WeaponIDToDisplayName( weaponID ) );
+ m_pCostImage = new TextImage( L"" );
+
+ m_pListBox = pParent;
+ BuyPresetWeapon weapon( weaponID );
+ SetWeapon( weapon );
+ }
+
+ virtual ~CWeaponButton() { delete m_pTitleImage; delete m_pCostImage; }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+
+ virtual Color GetBgColor() { return (IsCurrent()) ? m_selectedBgColor : Button::GetBgColor(); }
+ virtual Color GetFgColor() { return (IsCurrent()) ? m_selectedFgColor : Button::GetFgColor(); }
+
+ void SetCurrent() { s_current = this; }
+ bool IsCurrent() const { return s_current == this; }
+
+ void SetWeapon( const BuyPresetWeapon& weapon );
+ const BuyPresetWeapon& GetWeapon() { return m_weapon; }
+
+ virtual void Paint();
+ virtual void PerformLayout();
+ virtual void PaintBorder() {}
+
+ virtual void OnMousePressed( MouseCode code )
+ {
+ if ( code == MOUSE_LEFT )
+ {
+ SetCurrent();
+ m_pListBox->GetParent()->OnCommand( "select_weapon" );
+ }
+ Button::OnMousePressed( code );
+ }
+
+ virtual void OnMouseDoublePressed( MouseCode code )
+ {
+ if ( code == MOUSE_LEFT )
+ {
+ SetCurrent();
+ m_pListBox->GetParent()->OnCommand( "select_weapon" );
+ m_pListBox->GetParent()->OnCommand( "popup_ok" );
+ }
+ Button::OnMouseDoublePressed( code );
+ }
+
+protected:
+ static CWeaponButton * s_current;
+ BuyPresetListBox * m_pListBox;
+ BuyPresetWeapon m_weapon;
+
+ IImage *m_pImage;
+ TextImage *m_pTitleImage;
+ TextImage *m_pCostImage;
+ int m_imageWide;
+ int m_imageTall;
+ int m_imageX;
+ int m_imageY;
+
+ Color m_selectedBgColor;
+ Color m_selectedFgColor;
+
+ bool m_isPrimary;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+CWeaponButton * CWeaponButton::s_current = NULL;
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponButton::ApplySchemeSettings( IScheme *pScheme )
+{
+ CWeaponButton * current = s_current; // save off current so Button::ApplySchemeSettings() can get the right colors
+ s_current = NULL;
+ Button::ApplySchemeSettings( pScheme );
+ m_selectedBgColor = GetSchemeColor( "Button.ArmedBgColor", Button::GetBgColor(), pScheme );
+ m_selectedFgColor = GetSchemeColor( "Button.ArmedTextColor", Button::GetFgColor(), pScheme );
+ s_current = current;
+ m_pTitleImage->SetColor( pScheme->GetColor( "Button.TextColor", Color() ) );
+ m_pTitleImage->SetFont( pScheme->GetFont( "Default", IsProportional() ) );
+ m_pTitleImage->SetWrap( true );
+ m_pCostImage->SetColor( pScheme->GetColor( "Button.TextColor", Color() ) );
+ m_pCostImage->SetFont( pScheme->GetFont( "Default", IsProportional() ) );
+ m_pCostImage->SetWrap( true );
+ SetWeapon( m_weapon );
+ SetBorder( NULL );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponButton::SetWeapon( const BuyPresetWeapon& weapon )
+{
+ m_weapon = weapon;
+ if ( m_weapon.GetName() )
+ {
+ // weapon string
+ const wchar_t * name = m_weapon.GetName();
+ m_pTitleImage->SetText( name );
+
+ // cost string
+ CCSWeaponInfo *info = GetWeaponInfo( m_weapon.GetWeaponID() );
+ if ( info )
+ {
+ const int BufLen = 256;
+ wchar_t wbuf[BufLen];
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( info->GetWeaponPrice() ) );
+ m_pCostImage->SetText( wbuf );
+ }
+ else
+ {
+ m_pCostImage->SetText( L"" );
+ }
+ }
+ else
+ {
+ m_pTitleImage->SetText( L"" );
+ m_pCostImage->SetText( L"" );
+ }
+
+ m_pTitleImage->ResizeImageToContent();
+ m_pCostImage->ResizeImageToContent();
+
+ InvalidateLayout( true, false );
+
+ m_pImage = scheme()->GetImage( ImageFnameFromWeaponID( m_weapon.GetWeaponID(), m_isPrimary ), true );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponButton::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Calculate some sizes
+ int oldWide, oldTall;
+ GetSize( oldWide, oldTall );
+
+ const float IMAGE_PERCENT = 0.42f;
+ const float TITLE_PERCENT = 0.45f;
+ const float COST_PERCENT = 1.0f - TITLE_PERCENT - IMAGE_PERCENT;
+
+ int maxTitleWide = (int) oldWide * TITLE_PERCENT;
+ int maxImageWide = (int) oldWide * IMAGE_PERCENT;
+ int maxCostWide = (int) oldWide * COST_PERCENT;
+ int textTall = surface()->GetFontTall( m_pTitleImage->GetFont() ) * 2;
+ if ( oldTall != textTall )
+ {
+ oldTall = textTall;
+ SetSize( oldWide, oldTall );
+ m_pListBox->InvalidateLayout();
+ }
+
+ // Position the weapon name
+ {
+ m_pTitleImage->SetSize( maxTitleWide, oldTall );
+ m_pTitleImage->RecalculateNewLinePositions();
+ m_pTitleImage->ResizeImageToContent();
+
+ int textContentWide, textContentTall;
+ m_pTitleImage->GetSize( textContentWide, textContentTall );
+
+ if ( textContentTall < textTall )
+ {
+ m_pTitleImage->SetSize( maxTitleWide, textContentTall );
+ m_pTitleImage->SetPos( maxImageWide, (textTall - textContentTall) / 2 );
+ }
+ else
+ {
+ m_pTitleImage->SetPos( maxImageWide, 0 );
+ }
+ }
+
+ // Position the weapon cost
+ {
+ m_pCostImage->SetSize( maxCostWide, oldTall );
+ m_pCostImage->RecalculateNewLinePositions();
+ m_pCostImage->ResizeImageToContent();
+
+ int textContentWide, textContentTall;
+ m_pCostImage->GetSize( textContentWide, textContentTall );
+
+ if ( textContentTall < textTall )
+ {
+ m_pCostImage->SetSize( maxCostWide, textContentTall );
+ m_pCostImage->SetPos( oldWide - maxCostWide, (textTall - textContentTall) / 2 );
+ }
+ else
+ {
+ m_pCostImage->SetPos( oldWide - maxCostWide, 0 );
+ }
+ }
+
+
+ // Position the weapon image
+ m_pImage = scheme()->GetImage( ImageFnameFromWeaponID( m_weapon.GetWeaponID(), m_isPrimary ), true );
+
+ int maxImageTall = textTall;
+
+ m_pImage->GetContentSize( m_imageWide, m_imageTall );
+ if ( m_imageTall > maxImageTall )
+ {
+ m_imageWide = (int) m_imageWide * 1.0f * maxImageTall / m_imageTall;
+ m_imageTall = maxImageTall;
+ }
+ if ( m_imageWide > maxImageWide )
+ {
+ m_imageTall = (int) m_imageTall * 1.0f * maxImageWide / m_imageWide;
+ m_imageWide = maxImageWide;
+ }
+ m_imageY = (textTall - m_imageTall) / 2;
+ m_imageX = (((int) oldWide * IMAGE_PERCENT) - m_imageWide) / 2;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponButton::Paint()
+{
+ if ( m_pImage )
+ {
+ m_pImage->SetSize( m_imageWide, m_imageTall );
+ m_pImage->SetPos( m_imageX, m_imageY );
+ m_pImage->Paint();
+ m_pImage->SetSize( 0, 0 );
+ }
+ m_pTitleImage->Paint();
+ m_pCostImage->Paint();
+
+ BaseClass::Paint();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+class WeaponComboBox : public vgui::ComboBox
+{
+public:
+ WeaponComboBox( CWeaponSelectBox *parent, const char *name, int numEntries, bool editable )
+ : ComboBox( parent, name, numEntries, editable )
+ {
+ m_pBox = parent;
+ }
+
+ virtual void OnSetText( const wchar_t *newText )
+ {
+ ComboBox::OnSetText( newText );
+ if ( m_pBox )
+ m_pBox->UpdateClips();
+ }
+
+private:
+ CWeaponSelectBox *m_pBox;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+CWeaponSelectBox::CWeaponSelectBox(vgui::Panel *parent, WeaponSet *pWeaponSet, bool isSecondary ) : CCareerBaseBox(parent, "BuyBoxSelectWeapon", false)
+{
+ m_pWeaponSet = pWeaponSet;
+ m_isSecondary = isSecondary;
+
+ m_numWeapons = NUM_PRIMARY_WEAPONS;
+ m_weaponIDs = s_primaryWeapons;
+
+ BuyPresetWeapon *weapon;
+ if ( !m_isSecondary )
+ {
+ weapon = &m_pWeaponSet->m_primaryWeapon;
+ if ( !IsPrimaryWeapon( weapon->GetWeaponID() ) && weapon->GetWeaponID() != WEAPON_NONE )
+ {
+ BuyPresetWeapon tmp( WEAPON_NONE );
+ m_pWeaponSet->m_primaryWeapon = tmp;
+ }
+ }
+ else
+ {
+ m_numWeapons = NUM_SECONDARY_WEAPONS;
+ m_weaponIDs = s_secondaryWeapons;
+ weapon = &m_pWeaponSet->m_secondaryWeapon;
+ if ( !IsSecondaryWeapon( weapon->GetWeaponID() ) && weapon->GetWeaponID() != WEAPON_NONE )
+ {
+ BuyPresetWeapon tmp( WEAPON_NONE );
+ *weapon = tmp;
+ }
+ }
+
+ int maxClips = 0;
+ const CCSWeaponInfo *info = GetWeaponInfo( weapon->GetWeaponID() );
+ if ( info )
+ {
+ int maxRounds = GetCSAmmoDef()->MaxCarry( info->iAmmoType );
+ int buyClipSize = GetCSAmmoDef()->GetBuySize( info->iAmmoType );
+ maxClips = (buyClipSize > 0) ? ceil(maxRounds/(float)buyClipSize) : 0;
+ }
+ else
+ {
+ maxClips = NUM_CLIPS_FOR_CURRENT; // so we can buy ammo for our current gun
+ }
+
+ m_pClips = new WeaponComboBox( this, "Clips", 2*maxClips+1, false );
+ m_pClips->SetOpenDirection( Menu::UP );
+ m_pListBox = new BuyPresetListBox( this, "WeaponListBox" );
+ m_pBullets = new Label( this, "bullets", "" );
+
+ int selectedWeaponIndex = -1;
+ int i;
+ for ( i=0; i<m_numWeapons; ++i )
+ {
+ if ( m_weaponIDs[i] < 0 )
+ {
+ const char *text = "";
+ switch ( (int)m_weaponIDs[i] )
+ {
+ case -WEAPONTYPE_RIFLE:
+ text = "#Cstrike_BuyPresetCategoryRifle";
+ break;
+ case -WEAPONTYPE_SNIPER_RIFLE:
+ text = "#Cstrike_BuyPresetCategorySniper";
+ break;
+ case -WEAPONTYPE_SUBMACHINEGUN:
+ text = "#Cstrike_BuyPresetCategorySMG";
+ break;
+ case -WEAPONTYPE_SHOTGUN:
+ text = "#Cstrike_BuyPresetCategoryHeavy";
+ break;
+ }
+ Label *pLabel = new Label( m_pListBox, SharedVarArgs("weaponlabel%d", i), text );
+ m_pListBox->AddItem( pLabel, NULL );
+ }
+ else
+ {
+ CWeaponButton *pWeaponButton = new CWeaponButton( m_pListBox, m_weaponIDs[i], !m_isSecondary );
+ m_pListBox->AddItem( pWeaponButton, NULL );
+ if ( m_weaponIDs[i] == weapon->GetWeaponID() )
+ {
+ pWeaponButton->SetCurrent();
+ selectedWeaponIndex = i;
+ }
+ }
+ }
+ m_pListBox->MakeItemVisible( selectedWeaponIndex );
+
+ LoadControlSettings( "resource/UI/BuyPreset/BoxSelectWeapon.res" );
+ PopulateControls();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CWeaponSelectBox::~CWeaponSelectBox()
+{
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::ActivateBuildMode()
+{
+ SetClipsVisible( true );
+ m_pListBox->DeleteAllItems();
+ BaseClass::ActivateBuildMode();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::SetClipsVisible( bool visible )
+{
+ SetLabelVisible( visible );
+ m_pClips->SetVisible( visible );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::PopulateControls()
+{
+ BuyPresetWeapon *weapon;
+ if (!m_isSecondary)
+ {
+ weapon = &m_pWeaponSet->m_primaryWeapon;
+ }
+ else
+ {
+ weapon = &m_pWeaponSet->m_secondaryWeapon;
+ }
+
+ int i;
+ int maxClips = 0;
+ const CCSWeaponInfo *info = GetWeaponInfo( weapon->GetWeaponID() );
+ if ( info )
+ {
+ int maxRounds = GetCSAmmoDef()->MaxCarry( info->iAmmoType );
+ int buyClipSize = GetCSAmmoDef()->GetBuySize( info->iAmmoType );
+ maxClips = (buyClipSize > 0) ? ceil(maxRounds/(float)buyClipSize) : 0;
+ }
+ else
+ {
+ maxClips = NUM_CLIPS_FOR_CURRENT;
+ }
+ m_pClips->SetNumberOfEditLines( 2*maxClips+1 );
+
+ SetClipsVisible( maxClips != 0 );
+
+ m_pClips->DeleteAllItems();
+
+ // populate clips combo box
+ m_pClips->AddItem( "#Cstrike_BuyPresetEditWeaponFullClips", NULL );
+
+ const int BufLen = 64;
+ wchar_t buf[BufLen];
+ for ( i=maxClips-1; i>=0; --i )
+ {
+ const char* clipsOrMore = "#Cstrike_BuyPresetEditClipsOrMore";
+ const char* clips = "#Cstrike_BuyPresetEditClips";
+ if ( i == 1 )
+ {
+ clipsOrMore = "#Cstrike_BuyPresetEditClipOrMore";
+ clips = "#Cstrike_BuyPresetEditClip";
+ }
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf),
+ g_pVGuiLocalize->Find( clipsOrMore ),
+ 1, NumAsWString( i ));
+ m_pClips->AddItem( buf, NULL );
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf),
+ g_pVGuiLocalize->Find( clips ),
+ 1, NumAsWString( i ));
+ m_pClips->AddItem( buf, NULL );
+ }
+
+ // now select the proper entry
+ int clipIndexToSelect = weapon->GetFillAmmo();
+ clipIndexToSelect += 2 * weapon->GetAmmoAmount();
+ clipIndexToSelect = maxClips*2 - clipIndexToSelect;
+ m_pClips->ActivateItemByRow( clipIndexToSelect );
+
+ if ( m_isSecondary )
+ {
+ Panel *pPanel = FindChildByName( "TitleLabel" );
+ if ( pPanel )
+ {
+ const wchar_t *title = g_pVGuiLocalize->Find( "#Cstrike_BuyPresetWizardSecondary" );
+ if ( title )
+ PostMessage(pPanel, new KeyValues("SetText", "text", title));
+ }
+ }
+
+ UpdateClips();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::UpdateClips()
+{
+ if ( !m_pClips )
+ return;
+
+ int numEntries = m_pClips->GetItemCount();
+ int activeID = m_pClips->GetActiveItem();
+ int combined = numEntries - activeID + 1;
+ int numClips = combined/2 - 1;
+ //bool isFill = (combined%2) != 0;
+
+ BuyPresetWeapon *weapon;
+ if (!m_isSecondary)
+ {
+ weapon = &m_pWeaponSet->m_primaryWeapon;
+ }
+ else
+ {
+ weapon = &m_pWeaponSet->m_secondaryWeapon;
+ }
+
+ const CCSWeaponInfo *info = GetWeaponInfo( weapon->GetWeaponID() );
+ if ( info )
+ {
+ int maxRounds = GetCSAmmoDef()->MaxCarry( info->iAmmoType );
+ int buyClipSize = GetCSAmmoDef()->GetBuySize( info->iAmmoType );
+ m_pBullets->SetVisible( true );
+
+ const int BufLen = 64;
+ wchar_t buf[BufLen];
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetsBullets" ),
+ 2, NumAsWString( MIN( maxRounds, numClips * buyClipSize ) ), NumAsWString( maxRounds ) );
+ m_pBullets->SetText( buf );
+ }
+ else
+ {
+ m_pBullets->SetVisible( false );
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ HFont font = pScheme->GetFont("Default", IsProportional());
+ int tall = surface()->GetFontTall(font) + 2;
+ if ( font != INVALID_FONT )
+ {
+ Menu *pMenu = m_pClips->GetMenu();
+ pMenu->SetMenuItemHeight( tall );
+ }
+
+ for ( int i=0; i<m_pListBox->GetItemCount(); ++i )
+ {
+ if ( m_weaponIDs[i] >= 0 )
+ {
+ CWeaponButton *pButton = static_cast< CWeaponButton * >(m_pListBox->GetItemPanel(i));
+ if ( pButton && pButton->IsCurrent() )
+ {
+ m_pListBox->MakeItemVisible( i );
+ }
+ }
+ else
+ {
+ // it's a caption label
+ Label *pLabel = static_cast< Label * >(m_pListBox->GetItemPanel(i));
+ if ( pLabel )
+ {
+ pLabel->SetContentAlignment( Label::a_center );
+ pLabel->SetBorder( pScheme->GetBorder( "ButtonBorder" ) );
+ pLabel->SetBgColor( pScheme->GetColor( "Frame.BgColor", Color( 0, 0, 0, 255 ) ) );
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CSWeaponID CWeaponSelectBox::GetSelectedWeaponID()
+{
+ int selectedIndex = -1;
+ for ( int i=0; i<m_pListBox->GetItemCount(); ++i )
+ {
+ if ( m_weaponIDs[selectedIndex] >= 0 )
+ {
+ CWeaponButton *pButton = static_cast< CWeaponButton * >(m_pListBox->GetItemPanel(i));
+ if ( pButton && pButton->IsCurrent() )
+ {
+ selectedIndex = i;
+ }
+ }
+ }
+ if ( selectedIndex >= 0 )
+ {
+ return m_weaponIDs[selectedIndex];
+ }
+
+ return WEAPON_NONE;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CWeaponSelectBox::OnCommand(const char *command)
+{
+ if (!stricmp(command, "select_weapon"))
+ {
+ CSWeaponID weaponID = GetSelectedWeaponID();
+ BuyPresetWeapon weapon( weaponID );
+ if ( m_isSecondary )
+ {
+ m_pWeaponSet->m_secondaryWeapon = weapon;
+ }
+ else
+ {
+ m_pWeaponSet->m_primaryWeapon = weapon;
+ }
+
+ PopulateControls();
+ return;
+ }
+
+ if (!stricmp(command, "popup_ok"))
+ {
+ if ( !m_pClips )
+ return;
+
+ int numEntries = m_pClips->GetItemCount();
+ int activeID = m_pClips->GetActiveItem();
+ int combined = numEntries - activeID + 1;
+ int numClips = combined/2 - 1;
+ bool isFill = (combined%2) != 0;
+
+ BuyPresetWeapon weapon( GetSelectedWeaponID() );
+ weapon.SetAmmoType( AMMO_CLIPS );
+ weapon.SetAmmoAmount( numClips );
+ weapon.SetFillAmmo( isFill );
+
+ if ( m_isSecondary )
+ {
+ m_pWeaponSet->m_secondaryWeapon = weapon;
+ }
+ else
+ {
+ m_pWeaponSet->m_primaryWeapon = weapon;
+ }
+ BaseClass::OnCommand( command );
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+class EquipmentComboBox : public ComboBox
+{
+public:
+ EquipmentComboBox( CBaseSelectBox *parent, const char *name, int numEntries, bool editable )
+ : ComboBox( parent, name, numEntries, editable )
+ {
+ m_pBox = parent;
+ }
+
+ virtual void OnSetText( const wchar_t *newText )
+ {
+ ComboBox::OnSetText( newText );
+ m_pBox->OnControlChanged();
+ }
+
+private:
+ CBaseSelectBox *m_pBox;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+CGrenadeSelectBox::CGrenadeSelectBox( vgui::Panel *parent, WeaponSet *pWeaponSet ) : BaseClass( parent, "BuyBoxSelectGrenades", false )
+{
+ m_pWeaponSet = pWeaponSet;
+
+ // Equipment controls
+ m_pHEGrenade = new EquipmentComboBox( this, "hegrenade", 2, false );
+ m_pSmokeGrenade = new EquipmentComboBox( this, "smokegrenade", 2, false );
+ m_pFlashbangs = new EquipmentComboBox( this, "flashbangs", 3, false );
+
+ // Equipment images
+ m_pHEGrenadeImage = new EquipmentLabel( this, "HEGrenadeImage" );
+ m_pSmokeGrenadeImage = new EquipmentLabel( this, "SmokeGrenadeImage" );
+ m_pFlashbangImage = new EquipmentLabel( this, "FlashbangImage" );
+
+ m_pHELabel = new Label( this, "HECost", "" );
+ m_pSmokeLabel = new Label( this, "SmokeCost", "" );
+ m_pFlashLabel = new Label( this, "FlashCost", "" );
+
+ LoadControlSettings( "Resource/UI/BuyPreset/BoxSelectGrenades.res" );
+
+ // Add entries to the combo boxes
+ m_pHEGrenade->AddItem( "0", NULL );
+ m_pHEGrenade->AddItem( "1", NULL );
+
+ m_pSmokeGrenade->AddItem( "0", NULL );
+ m_pSmokeGrenade->AddItem( "1", NULL );
+
+ m_pFlashbangs->AddItem( "0", NULL );
+ m_pFlashbangs->AddItem( "1", NULL );
+ m_pFlashbangs->AddItem( "2", NULL );
+
+ // populate the data
+ m_pHEGrenade->ActivateItemByRow( m_pWeaponSet->m_HEGrenade );
+ m_pSmokeGrenade->ActivateItemByRow( m_pWeaponSet->m_smokeGrenade );
+ m_pFlashbangs->ActivateItemByRow( m_pWeaponSet->m_flashbangs );
+
+ m_pHEGrenadeImage->SetItem( "gfx/vgui/hegrenade_square", 1 );
+ m_pSmokeGrenadeImage->SetItem( "gfx/vgui/smokegrenade_square", 1 );
+ m_pFlashbangImage->SetItem( "gfx/vgui/flashbang_square", 1 );
+
+ OnControlChanged();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CGrenadeSelectBox::OnControlChanged()
+{
+ const int BufLen = 256;
+ wchar_t wbuf[BufLen];
+
+ CCSWeaponInfo *info;
+
+ int numGrenades;
+ info = GetWeaponInfo( WEAPON_HEGRENADE );
+ if ( info )
+ {
+ numGrenades = m_pHEGrenade->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( info->GetWeaponPrice() * numGrenades ) );
+ m_pHELabel->SetText( wbuf );
+ }
+
+ info = GetWeaponInfo( WEAPON_SMOKEGRENADE );
+ if ( info )
+ {
+ numGrenades = m_pSmokeGrenade->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( info->GetWeaponPrice() * numGrenades ) );
+ m_pSmokeLabel->SetText( wbuf );
+ }
+
+ info = GetWeaponInfo( WEAPON_FLASHBANG );
+ if ( info )
+ {
+ numGrenades = m_pFlashbangs->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( info->GetWeaponPrice() * numGrenades ) );
+ m_pFlashLabel->SetText( wbuf );
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CGrenadeSelectBox::OnCommand( const char *command )
+{
+ if (!stricmp(command, "popup_ok"))
+ {
+ // stuff values back in m_pWeaponSet
+ m_pWeaponSet->m_HEGrenade = m_pHEGrenade->GetActiveItem();
+ m_pWeaponSet->m_smokeGrenade = m_pSmokeGrenade->GetActiveItem();
+ m_pWeaponSet->m_flashbangs = m_pFlashbangs->GetActiveItem();
+ }
+ BaseClass::OnCommand( command );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+CEquipmentSelectBox::CEquipmentSelectBox( vgui::Panel *parent, WeaponSet *pWeaponSet ) : BaseClass( parent, "BuyBoxSelectEquipment", false )
+{
+ m_pWeaponSet = pWeaponSet;
+
+ // Equipment controls
+ m_pKevlar = new EquipmentComboBox( this, "kevlar", 2, false );
+ m_pHelmet = new EquipmentComboBox( this, "helmet", 2, false );
+ m_pDefuser = new EquipmentComboBox( this, "defuser", 2, false );
+ m_pNightvision = new EquipmentComboBox( this, "nightvision", 2, false );
+
+ // Equipment labels
+ m_pKevlarLabel = new Label( this, "kevlarCost", "" );
+ m_pHelmetLabel = new Label( this, "helmetCost", "" );
+ m_pDefuserLabel = new Label( this, "defuserCost", "" );
+ m_pNightvisionLabel = new Label( this, "nightvisionCost", "" );
+
+ // Equipment images
+ m_pKevlarImage = new EquipmentLabel( this, "KevlarImage" );
+ m_pHelmetImage = new EquipmentLabel( this, "HelmetImage" );
+ m_pDefuserImage = new EquipmentLabel( this, "DefuserImage" );
+ m_pNightvisionImage = new EquipmentLabel( this, "NightvisionImage" );
+
+ LoadControlSettings( "Resource/UI/BuyPreset/BoxSelectEquipment.res" );
+
+ // Add entries to the combo boxes
+ m_pKevlar->AddItem( "0", NULL );
+ m_pKevlar->AddItem( "1", NULL );
+
+ m_pHelmet->AddItem( "0", NULL );
+ m_pHelmet->AddItem( "1", NULL );
+
+ m_pDefuser->AddItem( "0", NULL );
+ m_pDefuser->AddItem( "1", NULL );
+
+ m_pNightvision->AddItem( "0", NULL );
+ m_pNightvision->AddItem( "1", NULL );
+
+ // populate the data
+ m_pKevlar->ActivateItemByRow( ( m_pWeaponSet->m_armor > 0 ) );
+ m_pHelmet->ActivateItemByRow( ( m_pWeaponSet->m_armor && m_pWeaponSet->m_helmet ) );
+ m_pDefuser->ActivateItemByRow( m_pWeaponSet->m_defuser );
+ m_pNightvision->ActivateItemByRow( m_pWeaponSet->m_nightvision );
+
+ m_pKevlarImage->SetItem( "gfx/vgui/kevlar", 1 );
+ m_pHelmetImage->SetItem( "gfx/vgui/helmet", 1 );
+ m_pDefuserImage->SetItem( "gfx/vgui/defuser", 1 );
+ m_pNightvisionImage->SetItem( "gfx/vgui/nightvision", 1 );
+
+ OnControlChanged();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CEquipmentSelectBox::OnControlChanged()
+{
+ const int BufLen = 256;
+ wchar_t wbuf[BufLen];
+
+ int iHelmetPrice = HELMET_PRICE;
+ int iKevlarPrice = KEVLAR_PRICE;
+ int iNVGPrice = NVG_PRICE;
+
+ if ( CSGameRules()->IsBlackMarket() )
+ {
+ iHelmetPrice = CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_ASSAULTSUIT ) - CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR );
+ iKevlarPrice = CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_KEVLAR );
+ iNVGPrice = CSGameRules()->GetBlackMarketPriceForWeapon( WEAPON_NVG );
+ }
+
+ int count = m_pKevlar->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( iKevlarPrice * count ) );
+ m_pKevlarLabel->SetText( wbuf );
+
+ m_pHelmet->SetEnabled( count );
+ if ( !count && m_pHelmet->GetActiveItem() )
+ m_pHelmet->ActivateItemByRow( 0 );
+
+ count = m_pHelmet->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( iHelmetPrice * count ) );
+ m_pHelmetLabel->SetText( wbuf );
+
+ count = m_pDefuser->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( DEFUSEKIT_PRICE * count ) );
+ m_pDefuserLabel->SetText( wbuf );
+
+ count = m_pNightvision->GetActiveItem();
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ),
+ g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ),
+ 1, NumAsWString( NVG_PRICE * count ) );
+ m_pNightvisionLabel->SetText( wbuf );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CEquipmentSelectBox::OnCommand( const char *command )
+{
+ if (!stricmp(command, "popup_ok"))
+ {
+ // stuff values back in m_pWeaponSet
+ m_pWeaponSet->m_armor = m_pKevlar->GetActiveItem() ? 100 : 0;
+ m_pWeaponSet->m_helmet = m_pWeaponSet->m_armor && m_pHelmet->GetActiveItem();
+ m_pWeaponSet->m_defuser = m_pDefuser->GetActiveItem();
+ m_pWeaponSet->m_nightvision = m_pNightvision->GetActiveItem();
+ }
+ BaseClass::OnCommand( command );
+}
+
+//--------------------------------------------------------------------------------------------------------------
diff --git a/game/client/cstrike/VGUI/career_box.h b/game/client/cstrike/VGUI/career_box.h
new file mode 100644
index 0000000..7506308
--- /dev/null
+++ b/game/client/cstrike/VGUI/career_box.h
@@ -0,0 +1,202 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+// Author: Matthew D. Campbell ([email protected]), 2003
+
+#ifndef CAREER_BOX_H
+#define CAREER_BOX_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/TextEntry.h>
+#include "weapon_csbase.h"
+#include "buy_presets/buy_presets.h"
+#include "buypreset_listbox.h"
+#include "buypreset_weaponsetlabel.h"
+
+class ConVarToggleCheckButton;
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Base class for career popup dialogs (handles custom backgrounds, etc)
+ */
+class CCareerBaseBox : public vgui::Frame
+{
+public:
+ CCareerBaseBox(vgui::Panel *parent, const char *panelName, bool loadResources = true, bool useCareerButtons = false );
+ virtual void ShowWindow();
+ void DoModal();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void PaintBackground();
+ virtual void PaintBorder();
+ virtual void PerformLayout();
+ void SetLabelText( const char *text );
+ void SetLabelText( const wchar_t *text );
+ void SetCancelButtonAsDefault();
+ vgui::Button * GetOkButton() { return m_pOkButton; }
+ virtual vgui::Panel *CreateControlByName(const char *controlName);
+
+private:
+ typedef vgui::Frame BaseClass;
+ vgui::Button *m_pOkButton;
+ vgui::Button *m_pCancelButton;
+ vgui::Dar<vgui::Button *> m_buttons;
+ vgui::Dar<ConVarToggleCheckButton *> m_conVarCheckButtons;
+
+ Color m_bgColor;
+ Color m_borderColor;
+ vgui::Label *m_pTextLabel;
+ bool m_cancelFocus;
+
+protected:
+ void SetLabelVisible( bool visible ) { m_pTextLabel->SetVisible( visible ); }
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+ virtual void OnCommand( const char *command ); ///< Handle button presses
+ void AddButton( vgui::Button *pButton ); ///< Add a button to our list of buttons for rollover sounds
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Popup dialog with functionality similar to QueryBox, bot with different layout
+ */
+class CCareerQueryBox : public CCareerBaseBox
+{
+public:
+ CCareerQueryBox(vgui::Panel *parent, const char *panelName, const char *resourceName = NULL);
+ CCareerQueryBox(const char *title, const char *labelText, const char *panelName, vgui::Panel *parent = NULL);
+ CCareerQueryBox(const wchar_t *title, const wchar_t *labelText, const char *panelName, vgui::Panel *parent = NULL);
+
+ virtual ~CCareerQueryBox();
+
+private:
+ typedef CCareerBaseBox BaseClass;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Popup dialog for selecting and editing a primary weapon (ammo to buy, side-availability)
+ */
+class CWeaponSelectBox : public CCareerBaseBox
+{
+public:
+ CWeaponSelectBox( vgui::Panel *parent, WeaponSet *pWeaponSet, bool isSecondary );
+
+ virtual ~CWeaponSelectBox();
+
+ virtual void ActivateBuildMode();
+
+ void UpdateClips();
+
+protected:
+ virtual void OnCommand( const char *command );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+private:
+ void PopulateControls();
+ void SetClipsVisible( bool visible );
+
+ CSWeaponID GetSelectedWeaponID();
+
+ typedef CCareerBaseBox BaseClass;
+ vgui::ComboBox *m_pClips; ///< Number of clips to purchase
+ vgui::Label *m_pBullets; ///< Label showing "M of N Bullets"
+
+ WeaponSet *m_pWeaponSet; ///< WeaponSet being edited
+ bool m_isSecondary; ///< is this weapon primary or secondary?
+ BuyPresetListBox *m_pListBox; ///< List of weapons from which to choose
+
+ int m_numWeapons;
+ CSWeaponID *m_weaponIDs;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Base class for editing grenades and equipment
+ */
+class CBaseSelectBox : public CCareerBaseBox
+{
+ typedef CCareerBaseBox BaseClass;
+
+public:
+ CBaseSelectBox( vgui::Panel *parent, const char *panelName, bool loadResources = true ) : BaseClass( parent, panelName, loadResources ) {}
+
+ virtual void OnControlChanged() = 0;
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Popup dialog for editing grenades in a buy preset fallback
+ */
+class CGrenadeSelectBox : public CBaseSelectBox
+{
+ typedef CBaseSelectBox BaseClass;
+
+public:
+ CGrenadeSelectBox( vgui::Panel *parent, WeaponSet *pWeaponSet );
+
+ void OnControlChanged(); ///< Updates item costs
+
+private:
+ WeaponSet *m_pWeaponSet; ///< WeaponSet being edited
+
+ // Equipment controls
+ vgui::ComboBox *m_pHEGrenade;
+ EquipmentLabel *m_pHEGrenadeImage;
+ vgui::Label *m_pHELabel;
+
+ vgui::ComboBox *m_pSmokeGrenade;
+ EquipmentLabel *m_pSmokeGrenadeImage;
+ vgui::Label *m_pSmokeLabel;
+
+ vgui::ComboBox *m_pFlashbangs;
+ EquipmentLabel *m_pFlashbangImage;
+ vgui::Label *m_pFlashLabel;
+
+ virtual void OnCommand( const char *command );
+};
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Popup dialog for selecting an equipment set
+ */
+class CEquipmentSelectBox : public CBaseSelectBox
+{
+ typedef CBaseSelectBox BaseClass;
+
+public:
+ CEquipmentSelectBox( vgui::Panel *parent, WeaponSet *pWeaponSet );
+
+ void OnControlChanged();
+
+private:
+ WeaponSet *m_pWeaponSet; ///< WeaponSet being edited
+
+ // Equipment controls
+ vgui::ComboBox *m_pKevlar;
+ vgui::Label *m_pKevlarLabel;
+ EquipmentLabel *m_pKevlarImage;
+
+ vgui::ComboBox *m_pHelmet;
+ vgui::Label *m_pHelmetLabel;
+ EquipmentLabel *m_pHelmetImage;
+
+ vgui::ComboBox *m_pDefuser;
+ vgui::Label *m_pDefuserLabel;
+ EquipmentLabel *m_pDefuserImage;
+
+ vgui::ComboBox *m_pNightvision;
+ vgui::Label *m_pNightvisionLabel;
+ EquipmentLabel *m_pNightvisionImage;
+
+ virtual void OnCommand( const char *command );
+};
+
+#endif // CAREER_BOX_H
diff --git a/game/client/cstrike/VGUI/career_button.cpp b/game/client/cstrike/VGUI/career_button.cpp
new file mode 100644
index 0000000..24bf779
--- /dev/null
+++ b/game/client/cstrike/VGUI/career_button.cpp
@@ -0,0 +1,189 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+#include <convar.h>
+#include "cdll_int.h"
+#include <ienginevgui.h>
+#include "filesystem.h"
+#include <vgui/ISystem.h>
+#include "career_button.h"
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/URLLabel.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui_controls/ScrollBar.h>
+#include <vgui_controls/BuildGroup.h>
+#include <vgui_controls/ImageList.h>
+#include <vgui_controls/TextImage.h>
+#include <vgui_controls/Button.h>
+
+#include "KeyValues.h"
+
+using namespace vgui;
+
+#ifndef _DEBUG
+#define PROPORTIONAL_CAREER_FRAMES 1
+#endif
+
+//--------------------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------------------
+CCareerButton::CCareerButton(vgui::Panel *parent, const char *buttonName, const char *buttonText, const char *image, bool textFirst) : BaseClass( parent, buttonName, "" )
+{
+ m_armedBorder = NULL;
+
+ m_textImage = new TextImage(buttonText);
+ m_image = scheme()->GetImage(image, true);
+ m_textFirst = textFirst;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerButton::SetImage( const char *image )
+{
+ m_image = scheme()->GetImage(image, true);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerButton::Paint()
+{
+ int buttonWide, buttonTall;
+ GetSize(buttonWide, buttonTall);
+
+ int imageWide, imageTall;
+ if ( m_image )
+ {
+ m_image->GetSize(imageWide, imageTall);
+ }
+ else
+ {
+ imageWide = imageTall = 0;
+ }
+
+ int textOffset = m_textPad;
+
+ if (m_textFirst)
+ {
+ if ( m_image )
+ {
+ m_image->SetPos(buttonWide - imageWide - m_imagePad, (buttonTall - imageTall)/2);
+ m_image->Paint();
+ }
+ }
+ else
+ {
+ if ( m_image )
+ {
+ m_image->SetPos(m_imagePad, (buttonTall - imageTall)/2);
+ m_image->Paint();
+ }
+ textOffset += imageWide + m_imagePad;
+ }
+
+ int textTall, textWide;
+ m_textImage->GetSize(textWide, textTall);
+
+ int textSpace = buttonWide - imageWide - m_imagePad - 2*m_textPad;
+
+ if ( IsEnabled() )
+ {
+ m_textImage->SetColor( m_textNormalColor );
+ }
+ else
+ {
+ m_textImage->SetColor( m_textDisabledColor );
+ }
+ m_textImage->SetPos(textOffset + (textSpace - textWide)/2, (buttonTall - textTall)/2);
+ m_textImage->Paint();
+
+ if (HasFocus() && IsEnabled() )
+ {
+ int x0, y0, x1, y1;
+ x0 = 3, y0 = 3, x1 = buttonWide - 4 , y1 = buttonTall - 2;
+ DrawFocusBorder(x0, y0, x1, y1);
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerButton::SetArmedBorder(IBorder *border)
+{
+ m_armedBorder = border;
+ InvalidateLayout(false);
+}
+
+//--------------------------------------------------------------------------------------------------------------
+IBorder* CCareerButton::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
+{
+ if ( /*_buttonBorderEnabled &&*/ armed && !depressed && IsEnabled() )
+ {
+ return m_armedBorder;
+ }
+
+ return BaseClass::GetBorder( depressed, armed, selected, keyfocus );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CCareerButton::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetDefaultBorder( pScheme->GetBorder("CareerButtonBorder") );
+ SetDepressedBorder( pScheme->GetBorder("CareerButtonDepressedBorder") );
+ m_armedBorder = pScheme->GetBorder("CareerButtonArmedBorder");
+
+ m_textNormalColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) );
+ m_textDisabledColor = pScheme->GetColor( "Label.DisabledFgColor2", Color(128, 128, 128, 255) );
+ m_textImage->SetColor( m_textNormalColor );
+ if ( m_image )
+ {
+ m_image->SetColor( GetFgColor() );
+ }
+
+ m_textImage->SetFont( pScheme->GetFont( "Default", IsProportional() ) );
+
+ m_textPad = atoi(pScheme->GetResourceString( "CareerButtonTextPad" ));
+ m_imagePad = atoi(pScheme->GetResourceString( "CareerButtonImagePad" ));
+ if (IsProportional())
+ {
+ m_textPad = scheme()->GetProportionalScaledValueEx( GetScheme(),m_textPad);
+ m_imagePad = scheme()->GetProportionalScaledValueEx( GetScheme(),m_imagePad);
+ }
+
+ const int BufLen = 128;
+ char buf[BufLen];
+ GetText(buf, BufLen);
+ m_textImage->SetText(buf);
+ m_textImage->ResizeImageToContent();
+
+ int buttonWide, buttonTall;
+ GetSize(buttonWide, buttonTall);
+
+ int imageWide, imageTall;
+ if ( m_image )
+ {
+ m_image->GetSize(imageWide, imageTall);
+ }
+ else
+ {
+ imageWide = imageTall = 0;
+ }
+
+ int textSpace = buttonWide - imageWide - m_imagePad - 2*m_textPad;
+
+ int textWide, textTall;
+ m_textImage->GetContentSize(textWide, textTall);
+ if (textSpace < textWide)
+ m_textImage->SetSize(textSpace, textTall);
+
+ Color bgColor = pScheme->GetColor( "CareerButtonBG", Color(0, 0, 0, 0) );
+ SetDefaultColor( bgColor, bgColor );
+ SetArmedColor( bgColor, bgColor );
+ SetDepressedColor( bgColor, bgColor );
+}
+
+//--------------------------------------------------------------------------------------------------------------
diff --git a/game/client/cstrike/VGUI/career_button.h b/game/client/cstrike/VGUI/career_button.h
new file mode 100644
index 0000000..96dabdd
--- /dev/null
+++ b/game/client/cstrike/VGUI/career_button.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef CAREER_BUTTON_H
+#define CAREER_BUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/BitmapImagePanel.h>
+#include <vgui_controls/PanelListPanel.h>
+#include <vgui_controls/Button.h>
+#include <vgui/KeyCode.h>
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * This class adds border functionality necessary for next/prev/start buttons on map and bot screens
+ */
+class CCareerButton : public vgui::Button
+{
+public:
+ CCareerButton(vgui::Panel *parent, const char *buttonName, const char *buttonText, const char *image, bool textFirst );
+
+ // Set armed button border attributes. Added in CCareerButton.
+ virtual void SetArmedBorder(vgui::IBorder *border);
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ virtual void Paint();
+
+ void SetImage( const char *image );
+
+protected:
+
+ // Get button border attributes.
+ virtual vgui::IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus);
+
+ vgui::IBorder *m_armedBorder;
+ vgui::IImage *m_image;
+ vgui::TextImage *m_textImage;
+ bool m_textFirst;
+ int m_textPad;
+ int m_imagePad;
+
+ Color m_textNormalColor;
+ Color m_textDisabledColor;
+
+private:
+ typedef vgui::Button BaseClass;
+};
+
+#endif // CAREER_BUTTON_H
diff --git a/game/client/cstrike/VGUI/counterstrikeviewport.cpp b/game/client/cstrike/VGUI/counterstrikeviewport.cpp
new file mode 100644
index 0000000..d1f8577
--- /dev/null
+++ b/game/client/cstrike/VGUI/counterstrikeviewport.cpp
@@ -0,0 +1,322 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Client DLL VGUI2 Viewport
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+
+#pragma warning( disable : 4800 ) // disable forcing int to bool performance warning
+
+// VGUI panel includes
+#include <vgui_controls/Panel.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+#include <vgui/Cursor.h>
+#include <vgui/IScheme.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <vgui/VGUI.h>
+
+// client dll/engine defines
+#include "hud.h"
+#include <voice_status.h>
+
+// cstrike specific dialogs
+#include "cstriketextwindow.h"
+#include "cstriketeammenu.h"
+#include "cstrikeclassmenu.h"
+#include "cstrikebuymenu.h"
+#include "cstrikebuyequipmenu.h"
+#include "cstrikespectatorgui.h"
+#include "cstrikeclientscoreboard.h"
+#include "clientmode_csnormal.h"
+#include "IGameUIFuncs.h"
+
+// viewport definitions
+#include <baseviewport.h>
+#include "counterstrikeviewport.h"
+#include "cs_gamerules.h"
+// #include "c_user_message_register.h"
+#include "vguicenterprint.h"
+#include "text_message.h"
+
+
+static void OpenPanelWithCheck( const char *panelToOpen, const char *panelToCheck )
+{
+ IViewPortPanel *checkPanel = gViewPortInterface->FindPanelByName( panelToCheck );
+ if ( !checkPanel || !checkPanel->IsVisible() )
+ {
+ gViewPortInterface->ShowPanel( panelToOpen, true );
+ }
+}
+
+
+CON_COMMAND( buyequip, "Show equipment buy menu" )
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if( pPlayer && pPlayer->m_lifeState == LIFE_ALIVE && pPlayer->State_Get() == STATE_ACTIVE )
+ {
+ if( !pPlayer->IsInBuyZone() )
+ {
+ internalCenterPrint->Print( "#Cstrike_NotInBuyZone" );
+ }
+ else if( CSGameRules()->IsBuyTimeElapsed() )
+ {
+ char strBuyTime[16];
+ Q_snprintf( strBuyTime, sizeof( strBuyTime ), "%d", (int)CSGameRules()->GetBuyTimeLength() );
+
+ wchar_t buffer[128];
+ wchar_t buytime[16];
+ g_pVGuiLocalize->ConvertANSIToUnicode( strBuyTime, buytime, sizeof(buytime) );
+ g_pVGuiLocalize->ConstructString( buffer, sizeof(buffer), g_pVGuiLocalize->Find("#Cstrike_TitlesTXT_Cant_buy"), 1, buytime );
+ internalCenterPrint->Print( buffer );
+ }
+ else
+ {
+ if( pPlayer->GetTeamNumber() == TEAM_CT )
+ {
+ OpenPanelWithCheck( PANEL_BUY_EQUIP_CT, PANEL_BUY_CT );
+ }
+ else if( pPlayer->GetTeamNumber() == TEAM_TERRORIST )
+ {
+ OpenPanelWithCheck( PANEL_BUY_EQUIP_TER, PANEL_BUY_TER );
+ }
+ }
+ }
+}
+
+CON_COMMAND( buymenu, "Show main buy menu" )
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if( pPlayer )
+ {
+ if ( pPlayer->m_lifeState != LIFE_ALIVE && pPlayer->State_Get() != STATE_ACTIVE )
+ return;
+
+ if( !pPlayer->IsInBuyZone() )
+ {
+ internalCenterPrint->Print( "#Cstrike_NotInBuyZone" );
+ }
+ else if( CSGameRules()->IsBuyTimeElapsed() )
+ {
+ char strBuyTime[16];
+ Q_snprintf( strBuyTime, sizeof( strBuyTime ), "%d", (int)CSGameRules()->GetBuyTimeLength() );
+
+ wchar_t buffer[128];
+ wchar_t buytime[16];
+ g_pVGuiLocalize->ConvertANSIToUnicode( strBuyTime, buytime, sizeof(buytime) );
+ g_pVGuiLocalize->ConstructString( buffer, sizeof(buffer), g_pVGuiLocalize->Find("#Cstrike_TitlesTXT_Cant_buy"), 1, buytime );
+ internalCenterPrint->Print( buffer );
+ }
+ else
+ {
+ if( pPlayer->GetTeamNumber() == TEAM_CT )
+ {
+ OpenPanelWithCheck( PANEL_BUY_CT, PANEL_BUY_EQUIP_CT );
+ }
+ else if( pPlayer->GetTeamNumber() == TEAM_TERRORIST )
+ {
+ OpenPanelWithCheck( PANEL_BUY_TER, PANEL_BUY_EQUIP_TER );
+ }
+ }
+ }
+}
+
+CON_COMMAND( chooseteam, "Choose a new team" )
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( pPlayer && pPlayer->CanShowTeamMenu() )
+ {
+ gViewPortInterface->ShowPanel( PANEL_TEAM, true );
+ }
+}
+
+CON_COMMAND_F( spec_help, "Show spectator help screen", FCVAR_CLIENTCMD_CAN_EXECUTE)
+{
+ if ( gViewPortInterface )
+ gViewPortInterface->ShowPanel( PANEL_INFO, true );
+}
+
+CON_COMMAND_F( spec_menu, "Activates spectator menu", FCVAR_CLIENTCMD_CAN_EXECUTE)
+{
+ bool bShowIt = true;
+
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( pPlayer && !pPlayer->IsObserver() )
+ return;
+
+ if ( args.ArgC() == 2 )
+ {
+ bShowIt = atoi( args[ 1 ] ) == 1;
+ }
+
+ if ( gViewPortInterface )
+ gViewPortInterface->ShowPanel( PANEL_SPECMENU, bShowIt );
+}
+
+CON_COMMAND_F( togglescores, "Toggles score panel", FCVAR_CLIENTCMD_CAN_EXECUTE)
+{
+ if ( !gViewPortInterface )
+ return;
+
+ IViewPortPanel *scoreboard = gViewPortInterface->FindPanelByName( PANEL_SCOREBOARD );
+
+ if ( !scoreboard )
+ return;
+
+ if ( scoreboard->IsVisible() )
+ {
+ gViewPortInterface->ShowPanel( scoreboard, false );
+ GetClientVoiceMgr()->StopSquelchMode();
+ }
+ else
+ {
+ gViewPortInterface->ShowPanel( scoreboard, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the VGUI subsystem starts up
+// Creates the sub panels and initialises them
+//-----------------------------------------------------------------------------
+void CounterStrikeViewport::Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 * pGameEventManager )
+{
+ BaseClass::Start( pGameUIFuncs, pGameEventManager );
+}
+
+void CounterStrikeViewport::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ gHUD.InitColors( pScheme );
+
+ SetPaintBackgroundEnabled( false );
+}
+
+
+IViewPortPanel* CounterStrikeViewport::CreatePanelByName(const char *szPanelName)
+{
+ IViewPortPanel* newpanel = NULL;
+
+ // overwrite MOD specific panel creation
+
+ if ( Q_strcmp(PANEL_SCOREBOARD, szPanelName) == 0)
+ {
+ newpanel = new CCSClientScoreBoardDialog( this );
+ }
+
+ else if ( Q_strcmp(PANEL_SPECGUI, szPanelName) == 0 )
+ {
+ newpanel = new CCSSpectatorGUI( this );
+ }
+
+ else if ( Q_strcmp(PANEL_CLASS_CT, szPanelName) == 0 )
+ {
+ newpanel = new CClassMenu_CT( this );
+ }
+
+ else if ( Q_strcmp(PANEL_CLASS_TER, szPanelName) == 0 )
+ {
+ newpanel = new CClassMenu_TER( this );
+ }
+
+ else if ( Q_strcmp(PANEL_BUY_CT, szPanelName) == 0 )
+ {
+ newpanel = new CCSBuyMenu_CT( this );
+ }
+
+ else if ( Q_strcmp(PANEL_BUY_TER, szPanelName) == 0 )
+ {
+ newpanel = new CCSBuyMenu_TER( this );
+ }
+
+ else if ( Q_strcmp(PANEL_BUY_EQUIP_CT, szPanelName) == 0 )
+ {
+ newpanel = new CCSBuyEquipMenu_CT( this );
+ }
+
+ else if ( Q_strcmp(PANEL_BUY_EQUIP_TER, szPanelName) == 0 )
+ {
+ newpanel = new CCSBuyEquipMenu_TER( this );
+ }
+
+ else if ( Q_strcmp(PANEL_TEAM, szPanelName) == 0 )
+ {
+ newpanel = new CCSTeamMenu( this );
+ }
+
+ else if ( Q_strcmp(PANEL_INFO, szPanelName) == 0 )
+ {
+ newpanel = new CCSTextWindow( this );
+ }
+
+ else
+ {
+ // create a generic base panel, don't add twice
+ newpanel = BaseClass::CreatePanelByName( szPanelName );
+ }
+
+ return newpanel;
+}
+
+void CounterStrikeViewport::CreateDefaultPanels( void )
+{
+ AddNewPanel( CreatePanelByName( PANEL_TEAM ), "PANEL_TEAM" );
+ AddNewPanel( CreatePanelByName( PANEL_CLASS_CT ), "PANEL_CLASS_CT" );
+ AddNewPanel( CreatePanelByName( PANEL_CLASS_TER ), "PANEL_CLASS_TER" );
+
+ AddNewPanel( CreatePanelByName( PANEL_BUY_CT ), "PANEL_BUY_CT" );
+ AddNewPanel( CreatePanelByName( PANEL_BUY_TER ), "PANEL_BUY_TER" );
+ AddNewPanel( CreatePanelByName( PANEL_BUY_EQUIP_CT ), "PANEL_BUY_EQUIP_CT" );
+ AddNewPanel( CreatePanelByName( PANEL_BUY_EQUIP_TER ), "PANEL_BUY_EQUIP_TER" );
+
+ BaseClass::CreateDefaultPanels();
+
+}
+
+int CounterStrikeViewport::GetDeathMessageStartHeight( void )
+{
+ int x = YRES(2);
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ x += g_pSpectatorGUI->GetTopBarHeight();
+ }
+
+ return x;
+}
+
+/*
+==========================
+HUD_ChatInputPosition
+
+Sets the location of the input for chat text
+==========================
+*/
+//MIKETODO: positioning of chat text (and other engine output)
+/*
+ #include "Exports.h"
+
+ void CL_DLLEXPORT HUD_ChatInputPosition( int *x, int *y )
+ {
+ RecClChatInputPosition( x, y );
+ if ( gViewPortInterface )
+ {
+ gViewPortInterface->ChatInputPosition( x, y );
+ }
+ }
+
+ EXPOSE_SINGLE_INTERFACE(CounterStrikeViewport, IClientVGUI, CLIENTVGUI_INTERFACE_VERSION);
+*/
diff --git a/game/client/cstrike/VGUI/counterstrikeviewport.h b/game/client/cstrike/VGUI/counterstrikeviewport.h
new file mode 100644
index 0000000..2559167
--- /dev/null
+++ b/game/client/cstrike/VGUI/counterstrikeviewport.h
@@ -0,0 +1,61 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef COUNTERSTRIKEVIEWPORT_H
+#define COUNTERSTRIKEVIEWPORT_H
+
+#include "cs_shareddefs.h"
+#include "baseviewport.h"
+
+
+using namespace vgui;
+
+namespace vgui
+{
+ class Panel;
+ class Label;
+ class CBitmapImagePanel;
+}
+
+class CCSTeamMenu;
+class CCSClassMenu;
+class CCSSpectatorGUI;
+class CCSClientScoreBoard;
+class CBuyMenu;
+class CCSClientScoreBoardDialog;
+
+
+
+//==============================================================================
+class CounterStrikeViewport : public CBaseViewport
+{
+
+private:
+ DECLARE_CLASS_SIMPLE( CounterStrikeViewport, CBaseViewport );
+
+public:
+
+ IViewPortPanel* CreatePanelByName(const char *szPanelName);
+ void CreateDefaultPanels( void );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 * pGameEventManager );
+
+ int GetDeathMessageStartHeight( void );
+
+ virtual void ShowBackGround(bool bShow)
+ {
+ m_pBackGround->SetVisible( false ); // CS:S menus paint their own backgrounds...
+ }
+
+private:
+ void CenterWindow( vgui::Frame *win );
+
+};
+
+
+#endif // COUNTERSTRIKEVIEWPORT_H
diff --git a/game/client/cstrike/VGUI/cstrikebuyequipmenu.cpp b/game/client/cstrike/VGUI/cstrikebuyequipmenu.cpp
new file mode 100644
index 0000000..ed8f013
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikebuyequipmenu.cpp
@@ -0,0 +1,111 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstrikebuyequipmenu.h"
+#include "cs_shareddefs.h"
+#include "cstrikebuysubmenu.h"
+#include "backgroundpanel.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor for CT Equipment menu
+//-----------------------------------------------------------------------------
+CCSBuyEquipMenu_CT::CCSBuyEquipMenu_CT(IViewPort *pViewPort) : CBuyMenu( pViewPort )
+{
+ SetTitle( "#Cstrike_Buy_Menu", true);
+
+ SetProportional( true );
+
+ m_pMainMenu = new CCSBuySubMenu( this, "BuySubMenu" );
+ m_pMainMenu->LoadControlSettings( "Resource/UI/BuyEquipment_CT.res" );
+ m_pMainMenu->SetVisible( false );
+
+ m_iTeam = TEAM_CT;
+
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor for Terrorist Equipment menu
+//-----------------------------------------------------------------------------
+CCSBuyEquipMenu_TER::CCSBuyEquipMenu_TER(IViewPort *pViewPort) : CBuyMenu( pViewPort )
+{
+ SetTitle( "#Cstrike_Buy_Menu", true);
+
+ SetProportional( true );
+
+ m_pMainMenu = new CCSBuySubMenu( this, "BuySubMenu" );
+ m_pMainMenu->LoadControlSettings( "Resource/UI/BuyEquipment_TER.res" );
+ m_pMainMenu->SetVisible( false );
+
+ m_iTeam = TEAM_TERRORIST;
+
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_CT::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_CT::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_CT::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_TER::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_TER::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBuyEquipMenu_TER::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
diff --git a/game/client/cstrike/VGUI/cstrikebuyequipmenu.h b/game/client/cstrike/VGUI/cstrikebuyequipmenu.h
new file mode 100644
index 0000000..425bd88
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikebuyequipmenu.h
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSTRIKEBUYEQUIPMENU_H
+#define CSTRIKEBUYEQUIPMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/WizardPanel.h>
+
+#include <buymenu.h>
+
+namespace vgui
+{
+ class Panel;
+}
+
+//============================
+// CT Equipment menu
+//============================
+class CCSBuyEquipMenu_CT : public CBuyMenu
+{
+private:
+ typedef vgui::WizardPanel BaseClass;
+
+public:
+ CCSBuyEquipMenu_CT(IViewPort *pViewPort);
+
+ virtual const char *GetName( void ) { return PANEL_BUY_EQUIP_CT; }
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+
+//============================
+// Terrorist Equipment menu
+//============================
+
+class CCSBuyEquipMenu_TER : public CBuyMenu
+{
+private:
+ typedef vgui::WizardPanel BaseClass;
+
+public:
+ CCSBuyEquipMenu_TER(IViewPort *pViewPort);
+
+ virtual const char *GetName( void ) { return PANEL_BUY_EQUIP_TER; }
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+#endif // CSTRIKEBUYEQUIPMENU_H
diff --git a/game/client/cstrike/VGUI/cstrikebuymenu.cpp b/game/client/cstrike/VGUI/cstrikebuymenu.cpp
new file mode 100644
index 0000000..e637c89
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikebuymenu.cpp
@@ -0,0 +1,883 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstrikebuysubmenu.h"
+#include "cstrikebuymenu.h"
+#include "cs_shareddefs.h"
+#include "backgroundpanel.h"
+#include "buy_presets/buy_presets.h"
+#include "cstrike/bot/shared_util.h"
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include "buypreset_weaponsetlabel.h"
+#include "career_box.h"
+#include "cs_gamerules.h"
+#include "vgui_controls/RichText.h"
+#include "cs_weapon_parse.h"
+#include "c_cs_player.h"
+#include "cs_ammodef.h"
+
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+/**
+ * This button resizes any images to fit in the width/height constraints
+ */
+class BuyPresetButton : public vgui::Button
+{
+ typedef vgui::Button BaseClass;
+
+public:
+ BuyPresetButton(vgui::Panel *parent, const char *buttonName, const char *buttonText );
+ virtual ~BuyPresetButton();
+
+ virtual void PerformLayout( void );
+ virtual void ClearImages( void );
+
+ virtual void SetFgColor( Color c )
+ {
+ BaseClass::SetFgColor( c );
+ }
+
+ void SetAvailable( bool available )
+ {
+ m_available = available;
+ }
+
+ virtual int AddImage( vgui::IImage *image, int offset )
+ {
+ if ( image )
+ {
+ if ( !m_available )
+ {
+ image->SetColor( Color( 128, 128, 128, 255 ) );
+ }
+ }
+ return BaseClass::AddImage( image, offset );
+ }
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
+ {
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_availableColor = pScheme->GetColor( "Label.TextColor", Color( 0, 0, 0, 0 ) );
+ m_unavailableColor = pScheme->GetColor( "Label.DisabledFgColor2", Color( 0, 0, 0, 0 ) );
+ }
+
+ virtual Color GetButtonFgColor( void )
+ {
+ return ( m_available ) ? m_availableColor : m_unavailableColor;
+ }
+
+private:
+
+ bool m_available;
+ Color m_availableColor;
+ Color m_unavailableColor;
+};
+
+//-----------------------------------------------------------------------------
+BuyPresetButton::BuyPresetButton(vgui::Panel *parent, const char *buttonName, const char *buttonText ) : Button( parent, buttonName, buttonText )
+{
+ m_available = false;
+}
+
+//-----------------------------------------------------------------------------
+BuyPresetButton::~BuyPresetButton()
+{
+ ClearImages();
+}
+
+//-----------------------------------------------------------------------------
+void BuyPresetButton::ClearImages( void )
+{
+ int imageCount = GetImageCount();
+ for ( int i=0; i<imageCount; ++i )
+ {
+ BuyPresetImage *image = dynamic_cast< BuyPresetImage * >(GetImageAtIndex( i ));
+ if ( image )
+ {
+ delete image;
+ }
+ }
+
+ Button::ClearImages();
+}
+
+//-----------------------------------------------------------------------------
+void BuyPresetButton::PerformLayout( void )
+{
+ // resize images
+ int imageCount = GetImageCount();
+ if ( imageCount > 1 )
+ {
+ int wide, tall;
+ GetSize( wide, tall );
+
+ for ( int i=1; i<imageCount; ++i )
+ {
+ IImage *image = GetImageAtIndex( i );
+ if ( image )
+ {
+ int imageWide, imageTall;
+ image->GetSize( imageWide, imageTall );
+
+ float scaleX = 1.0f, scaleY = 1.0f;
+ float widthPercent = 0.2f;
+ if ( i == 1 )
+ {
+ widthPercent = 0.6f;
+ }
+
+ if ( imageWide > wide * widthPercent )
+ {
+ scaleX = (float)wide * widthPercent / (float)imageWide;
+ }
+ if ( imageTall > tall )
+ {
+ scaleY = (float)tall / (float)imageTall;
+ }
+
+ float scale = MIN( scaleX, scaleY );
+ if ( scale < 1.0f )
+ {
+ imageWide *= scale;
+ imageTall *= scale;
+ image->SetSize( imageWide, imageTall );
+ }
+ }
+ }
+ }
+
+ Button::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSBuyMenu_CT::CCSBuyMenu_CT(IViewPort *pViewPort) : CCSBaseBuyMenu( pViewPort, "BuySubMenu_CT" )
+{
+ m_pMainMenu->LoadControlSettings( "Resource/UI/BuyMenu_CT.res" );
+ m_pMainMenu->SetVisible( false );
+
+ m_iTeam = TEAM_CT;
+
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSBuyMenu_TER::CCSBuyMenu_TER(IViewPort *pViewPort) : CCSBaseBuyMenu( pViewPort, "BuySubMenu_TER" )
+{
+ m_pMainMenu->LoadControlSettings( "Resource/UI/BuyMenu_TER.res" );
+ m_pMainMenu->SetVisible( false );
+
+ m_iTeam = TEAM_TERRORIST;
+
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSBaseBuyMenu::CCSBaseBuyMenu(IViewPort *pViewPort, const char *subPanelName) : CBuyMenu( pViewPort )
+{
+ SetTitle( "#Cstrike_Buy_Menu", true);
+
+ SetProportional( true );
+
+ m_pMainMenu = new CCSBuySubMenu( this, subPanelName );
+ m_pMainMenu->SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
+#if USE_BUY_PRESETS
+ for ( int i=0; i<NUM_BUY_PRESET_BUTTONS; ++i )
+ {
+ m_pBuyPresetButtons[i] = new BuyPresetButton( m_pMainMenu, VarArgs( "BuyPresetButton%c", 'A' + i ), "" );
+ }
+ m_pMoney = new Label( m_pMainMenu, "money", "" );
+ //=============================================================================
+ // HPE_BEGIN:
+ // [pfreese] mainBackground was the little orange box outside that buy window
+ // that shouldn't have been there. Maybe this was left over from some
+ // copied code.
+ //=============================================================================
+
+ m_pMainBackground = NULL;
+// m_pMainBackground = new Panel( m_pMainMenu, "mainBackground" );
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+ m_pLoadout = new BuyPresetEditPanel( m_pMainMenu, "loadoutPanel", "Resource/UI/Loadout.res", 0, false );
+#else
+ for ( int i=0; i<NUM_BUY_PRESET_BUTTONS; ++i )
+ {
+ m_pBuyPresetButtons[i] = NULL;
+ }
+ m_pMoney = NULL;
+ m_pMainBackground = NULL;
+#endif // USE_BUY_PRESETS
+ m_lastMoney = -1;
+
+ m_pBlackMarket = new EditablePanel( m_pMainMenu, "BlackMarket_Bargains" );
+ m_pBlackMarket->LoadControlSettings( "Resource/UI/BlackMarket_Bargains.res" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if ( state )
+ {
+ Panel *defaultButton = FindChildByName( "CancelButton" );
+ if ( defaultButton )
+ {
+ defaultButton->RequestFocus();
+ }
+ SetMouseInputEnabled( true );
+ m_pMainMenu->SetMouseInputEnabled( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: shows/hides the buy menu
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::ShowPanel(bool bShow)
+{
+ CBuyMenu::ShowPanel( bShow );
+
+#if USE_BUY_PRESETS
+ if ( bShow )
+ {
+ UpdateBuyPresets( true );
+ }
+#endif // USE_BUY_PRESETS
+}
+
+//-----------------------------------------------------------------------------
+static void GetPanelBounds( Panel *pPanel, wrect_t& bounds )
+{
+ if ( !pPanel )
+ {
+ bounds.bottom = bounds.left = bounds.right = bounds.top = 0;
+ }
+ else
+ {
+ pPanel->GetBounds( bounds.left, bounds.top, bounds.right, bounds.bottom );
+ bounds.right += bounds.left;
+ bounds.bottom += bounds.top;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::Paint()
+{
+#if USE_BUY_PRESETS
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+ int account = (pPlayer) ? pPlayer->GetAccount() : 0;
+
+ if ( m_pMoney && m_lastMoney != account )
+ {
+ m_lastMoney = account;
+
+ const int BufLen = 128;
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_Current_Money");
+ if ( !formatStr )
+ formatStr = L"%s1";
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, NumAsWString( m_lastMoney ) );
+ m_pMoney->SetText( wbuf );
+ }
+#endif // USE_BUY_PRESETS
+
+ CBuyMenu::Paint();
+}
+
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::UpdateBuyPresets( bool showDefaultPanel )
+{
+ bool setPanelVisible = false;
+ if ( !showDefaultPanel )
+ {
+ setPanelVisible = true;
+ }
+
+ if ( !TheBuyPresets )
+ TheBuyPresets = new BuyPresetManager();
+
+ int i;
+ // show buy preset buttons
+ int numPresets = MIN( TheBuyPresets->GetNumPresets(), NUM_BUY_PRESET_BUTTONS );
+ for ( i=0; i<numPresets; ++i )
+ {
+ if ( !m_pBuyPresetButtons[i] )
+ continue;
+
+ const BuyPreset *preset = TheBuyPresets->GetPreset(i);
+
+ int setIndex;
+ int currentCost = -1;
+ WeaponSet currentSet;
+ const WeaponSet *fullSet = NULL;
+ for ( setIndex = 0; setIndex < preset->GetNumSets(); ++setIndex )
+ {
+ const WeaponSet *itemSet = preset->GetSet( setIndex );
+ if ( itemSet )
+ {
+ itemSet->GetCurrent( currentCost, currentSet );
+ if ( currentCost >= 0 )
+ {
+ fullSet = itemSet;
+ break;
+ }
+ }
+ }
+
+ if ( !fullSet && preset->GetNumSets() )
+ {
+ fullSet = preset->GetSet( 0 );
+ }
+
+ // set the button's images
+ m_pBuyPresetButtons[i]->ClearImages();
+ m_pBuyPresetButtons[i]->SetTextImageIndex( 0 );
+ m_pBuyPresetButtons[i]->SetText( "" );
+
+ m_pBuyPresetButtons[i]->SetAvailable( currentCost >= 0 );
+
+ const char *imageName = "";
+ if ( fullSet )
+ {
+ if ( fullSet->GetPrimaryWeapon().GetWeaponID() != WEAPON_NONE )
+ {
+ imageName = ImageFnameFromWeaponID( fullSet->GetPrimaryWeapon().GetWeaponID(), true );
+ BuyPresetImage * image = new BuyPresetImage( scheme()->GetImage(imageName, true) );
+ m_pBuyPresetButtons[i]->AddImage( image, 0 );
+ }
+ if ( fullSet->GetSecondaryWeapon().GetWeaponID() != WEAPON_NONE )
+ {
+ imageName = ImageFnameFromWeaponID( fullSet->GetSecondaryWeapon().GetWeaponID(), false );
+ BuyPresetImage * image = new BuyPresetImage( scheme()->GetImage(imageName, true) );
+ m_pBuyPresetButtons[i]->AddImage( image, 0 );
+ }
+ }
+
+ int displayCost = currentCost;
+ if ( displayCost < 0 )
+ displayCost = 0;
+
+ const int BufLen = 1024;
+ char aBuf[BufLen];
+ Q_snprintf(aBuf, BufLen, "#Cstrike_BuyMenuPreset%d", i + 1);
+ m_pBuyPresetButtons[i]->SetText( g_pVGuiLocalize->Find(aBuf) );
+ Q_snprintf(aBuf, BufLen, "cl_buy_favorite %d", i + 1);
+ m_pBuyPresetButtons[i]->SetCommand( aBuf );
+ m_pBuyPresetButtons[i]->SetVisible( true );
+ m_pBuyPresetButtons[i]->SetEnabled( true );
+ }
+
+ // hide unused buy preset buttons
+ for ( i=numPresets+1; i<NUM_BUY_PRESET_BUTTONS; ++i )
+ {
+ if ( m_pBuyPresetButtons[i] )
+ {
+ m_pBuyPresetButtons[i]->SetVisible( false );
+ m_pBuyPresetButtons[i]->SetEnabled( true );
+ }
+ }
+
+ HandleBlackMarket();
+}
+
+const char *g_pWeaponNames[] =
+{
+ " ",
+ "#Cstrike_TitlesTXT_P228",
+ "#Cstrike_TitlesTXT_Glock18",
+ "#Cstrike_TitlesTXT_Scout",
+ "#Cstrike_TitlesTXT_HE_Grenade",
+ "#Cstrike_TitlesTXT_XM1014",
+ " ",
+ "#Cstrike_TitlesTXT_Mac10",
+ "#Cstrike_TitlesTXT_Aug",
+ "#Cstrike_TitlesTXT_Smoke_Grenade",
+ "#Cstrike_TitlesTXT_Dual40",
+ "#Cstrike_TitlesTXT_FiveSeven",
+ "#Cstrike_TitlesTXT_UMP45",
+ "#Cstrike_TitlesTXT_SG550",
+ "#Cstrike_TitlesTXT_Galil",
+ "#Cstrike_TitlesTXT_Famas",
+ "#Cstrike_TitlesTXT_USP45",
+ "#Cstrike_TitlesTXT_Magnum",
+ "#Cstrike_TitlesTXT_mp5navy",
+ "#Cstrike_TitlesTXT_ESM249",
+ "#Cstrike_TitlesTXT_Leone12",
+ "#Cstrike_TitlesTXT_M4A1",
+ "#Cstrike_TitlesTXT_tmp",
+ "#Cstrike_TitlesTXT_G3SG1",
+ "#Cstrike_TitlesTXT_Flashbang",
+ "#Cstrike_TitlesTXT_DesertEagle",
+ "#Cstrike_TitlesTXT_SG552",
+ "#Cstrike_TitlesTXT_AK47",
+ " ",
+ "#Cstrike_TitlesTXT_FNP90",
+ " ",
+ "#Cstrike_TitlesTXT_Kevlar_Vest",
+ "#Cstrike_TitlesTXT_Kevlar_Vest_Ballistic_Helmet",
+ "#Cstrike_TitlesTXT_Nightvision_Goggles"
+};
+
+int GetWeeklyBargain( void )
+{
+ if ( CSGameRules() == NULL || CSGameRules()->m_pPrices == NULL )
+ return 0;
+
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( pPlayer == NULL )
+ return 0;
+
+ int iBestIndex = 0;
+ int iBestBargain = 99999;
+
+ for ( int i = 1; i < WEAPON_MAX; i++ )
+ {
+ if ( i == WEAPON_SHIELDGUN )
+ continue;
+
+ CCSWeaponInfo *info = GetWeaponInfo( (CSWeaponID)i );
+
+ if ( info == NULL )
+ continue;
+
+ if ( info->m_iTeam == TEAM_UNASSIGNED || info->m_iTeam == pPlayer->m_iTeamNum )
+ {
+ int iBargain = info->GetWeaponPrice() - info->GetPrevousPrice();
+
+ if ( iBargain < iBestBargain )
+ {
+ iBestIndex = i;
+ iBestBargain = iBargain;
+ }
+ }
+ }
+
+ return iBestIndex;
+}
+
+#ifdef _DEBUG
+ConVar cs_testbargain( "cs_testbargain", "1" );
+#endif
+
+void CCSBaseBuyMenu::HandleBlackMarket( void )
+{
+ if ( CSGameRules() == NULL )
+ return;
+
+ if ( m_pLoadout )
+ {
+ if ( CSGameRules()->IsBlackMarket() )
+ {
+ if ( CSGameRules()->m_pPrices == NULL )
+ return;
+
+ if ( m_pBlackMarket == NULL )
+ return;
+
+ int iBargain = GetWeeklyBargain();
+ CCSWeaponInfo *info = GetWeaponInfo( (CSWeaponID)iBargain );
+
+ wchar_t *wszWeaponName = g_pVGuiLocalize->Find( g_pWeaponNames[iBargain]);
+
+ if ( wszWeaponName == NULL )
+ return;
+
+ if ( info == NULL )
+ return;
+
+ m_pLoadout->SetVisible( false );
+ Label *pLabel = dynamic_cast< Label * >(m_pMainMenu->FindChildByName( "loadoutLabel" ));
+
+ if ( pLabel )
+ {
+ pLabel->SetVisible( false );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarket->FindChildByName( "MarketHeadline" ));
+
+ if ( pLabel )
+ {
+ const int BufLen = 2048;
+
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketHeadline");
+
+ if ( !formatStr )
+ formatStr = L"%s1";
+
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, wszWeaponName );
+ pLabel->SetText( wbuf );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarket->FindChildByName( "MarketBargain" ));
+
+ if ( pLabel )
+ {
+ const int BufLen = 2048;
+ wchar_t wbuf[BufLen] = L"";
+ const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketBargain");
+
+ if ( !formatStr )
+ formatStr = L"%s1";
+
+ g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, wszWeaponName );
+ pLabel->SetText( wbuf );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarket->FindChildByName( "MarketStickerPrice" ));
+
+ if ( pLabel )
+ {
+ char wbuf[16];
+
+ Q_snprintf( wbuf, 16, "%d", CSGameRules()->m_pPrices->iCurrentPrice[iBargain] );
+
+ pLabel->SetText( wbuf );
+ }
+
+ RichText *pText = dynamic_cast< RichText * >(m_pBlackMarket->FindChildByName( "MarketDescription" ));
+
+ if ( pText )
+ {
+ char wbuf[2048];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find("#Cstrike_MarketDescription"), wbuf, 2048 );
+
+ pText->SetText( "" );
+ pText->InsertPossibleURLString( wbuf, Color( 255, 255, 255, 255 ), Color( 255, 176, 0, 255 ) );
+ pText->SetVerticalScrollbar( false );
+ pText->SetPaintBorderEnabled( false );
+ pText->SetUnderlineFont( m_hUnderlineFont );
+ }
+
+ pLabel = dynamic_cast< Label * >(m_pBlackMarket->FindChildByName( "MarketBargainIcon" ));
+
+ if ( pLabel )
+ {
+ char wbuff[12];
+ Q_snprintf( wbuff, 12, "%c", info->iconActive->cCharacterInFont );
+
+ pLabel->SetText( wbuff );
+ }
+
+ Button *pButton = dynamic_cast< Button * >(m_pMainMenu->FindChildByName( "BargainbuyButton" ));
+
+ if ( pButton )
+ {
+ char command[512];
+ char *pWeaponName = Q_stristr( info->szClassName, "_" );
+
+ if ( pWeaponName )
+ {
+ pWeaponName++;
+
+ Q_snprintf( command, 512, "buy %s", pWeaponName );
+ }
+
+ pButton->SetCommand( command );
+ pButton->SetVisible( true );
+ }
+
+
+ m_pBlackMarket->SetVisible( true );
+ m_pBlackMarket->SetZPos( -2 );
+ }
+ else
+ {
+ WeaponSet ws;
+
+ TheBuyPresets->GetCurrentLoadout( &ws );
+ m_pLoadout->SetWeaponSet( &ws, true );
+
+ m_pLoadout->SetVisible( true );
+ Panel *pLabel = dynamic_cast< Label * >(m_pMainMenu->FindChildByName( "loadoutLabel" ));
+
+ if ( pLabel )
+ {
+ pLabel->SetVisible( true );
+ }
+
+ if ( m_pBlackMarket )
+ {
+ m_pBlackMarket->SetVisible( false );
+
+ Button *pButton = dynamic_cast< Button * >(m_pMainMenu->FindChildByName( "BargainbuyButton" ));
+
+ if ( pButton )
+ {
+ pButton->SetVisible( false );
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBaseBuyMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+
+ if ( m_pMainBackground )
+ {
+ m_pMainBackground->SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
+ m_pMainBackground->SetBgColor( GetSchemeColor( "Button.BgColor", GetBgColor(), pScheme ) );
+ }
+
+ m_hUnderlineFont = pScheme->GetFont( "CSUnderline", IsProportional() );
+
+#if USE_BUY_PRESETS
+ UpdateBuyPresets( true );
+#endif // USE_BUY_PRESETS
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static bool IsWeaponInvalid( CSWeaponID weaponID )
+{
+ if ( weaponID == WEAPON_NONE )
+ return false;
+
+ return !CanBuyWeapon( WEAPON_NONE, WEAPON_NONE, weaponID );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBuySubMenu::OnThink()
+{
+ UpdateVestHelmPrice();
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: When buying vest+helmet, if you already have a vest with no damage
+// then the price is reduced to just the helmet. Because this can change during
+// the game, we need to update the enable/disable state of the menu item dynamically.
+//-----------------------------------------------------------------------------
+void CCSBuySubMenu::UpdateVestHelmPrice()
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( pPlayer == NULL )
+ return;
+
+ BuyMouseOverPanelButton *pButton = dynamic_cast< BuyMouseOverPanelButton * > ( FindChildByName( "kevlar_helmet", false ) );
+ if ( pButton )
+ {
+ // Set its price to the current value from the player.
+ pButton->SetCurrentPrice( pPlayer->GetCurrentAssaultSuitPrice() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBuySubMenu::OnCommand( const char *command )
+{
+#if USE_BUY_PRESETS
+ const char *buyPresetSetString = "cl_buy_favorite_query_set ";
+ if ( !strnicmp( command, buyPresetSetString, strlen( buyPresetSetString ) ) )
+ {
+ bool invalid = IsWeaponInvalid( GetClientWeaponID( true ) ) || IsWeaponInvalid( GetClientWeaponID( false ) );
+ if ( invalid )
+ {
+ // can't save the favorite because it has an invalid weapon (colt for a T, etc)
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( pPlayer )
+ {
+ pPlayer->EmitSound( "BuyPreset.CantBuy" );
+ }
+
+ if ( cl_buy_favorite_nowarn.GetBool() )
+ {
+ BaseClass::OnCommand( "vguicancel" );
+ }
+ else
+ {
+ CCareerQueryBox *pBox = new CCareerQueryBox( this, "SetLoadoutError", "Resource/UI/SetLoadoutError.res" );
+ pBox->AddActionSignalTarget( this );
+ pBox->DoModal();
+ }
+ }
+ else
+ {
+ // can save
+ if ( cl_buy_favorite_quiet.GetBool() )
+ {
+ BaseClass::OnCommand( VarArgs( "cl_buy_favorite_set %d", atoi( command + strlen( buyPresetSetString ) ) ) );
+ }
+ else
+ {
+ CCareerQueryBox *pBox = new CCareerQueryBox( this, "SetLoadoutQuery", "Resource/UI/SetLoadoutQuery.res" );
+ pBox->SetCancelButtonAsDefault();
+ if ( pBox->GetOkButton() )
+ {
+ pBox->GetOkButton()->SetCommand( VarArgs( "cl_buy_favorite_set %d", atoi( command + strlen( buyPresetSetString ) ) ) );
+ }
+ pBox->AddActionSignalTarget( this );
+ pBox->DoModal();
+ }
+ }
+ return;
+ }
+#endif // USE_BUY_PRESETS
+
+ if ( FStrEq( command, "buy_unavailable" ) )
+ {
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( pPlayer )
+ {
+ pPlayer->EmitSound( "BuyPreset.CantBuy" );
+ }
+ BaseClass::OnCommand( "vguicancel" );
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void CCSBuySubMenu::OnSizeChanged(int newWide, int newTall)
+{
+ m_backgroundLayoutFinished = false;
+ BaseClass::OnSizeChanged( newWide, newTall );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSBuySubMenu::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Buy submenus need to be shoved over for widescreen
+ int screenW, screenH;
+ GetHudSize( screenW, screenH );
+
+ int fullW, fullH;
+ fullW = scheme()->GetProportionalScaledValueEx( GetScheme(), 640 );
+ fullH = scheme()->GetProportionalScaledValueEx( GetScheme(), 480 );
+
+ fullW = GetAlternateProportionalValueFromScaled( GetScheme(), fullW );
+ fullH = GetAlternateProportionalValueFromScaled( GetScheme(), fullH );
+
+ int offsetX = (screenW - fullW)/2;
+ int offsetY = (screenH - fullH)/2;
+
+ if ( !m_backgroundLayoutFinished )
+ ResizeWindowControls( this, GetWide(), GetTall(), offsetX, offsetY );
+ m_backgroundLayoutFinished = true;
+
+ HandleBlackMarket();
+}
+
+void CCSBuySubMenu::HandleBlackMarket( void )
+{
+ if ( CSGameRules() == NULL )
+ return;
+
+ int iBestBargain = 99999;
+ BuyMouseOverPanelButton *pButtonBargain = NULL;
+
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ BuyMouseOverPanelButton *pButton = dynamic_cast< BuyMouseOverPanelButton * > ( GetChild(i) );
+ if (!pButton)
+ continue;
+
+ pButton->SetBargainButton( false );
+
+ const char *pWeaponName = Q_stristr( pButton->GetBuyCommand(), " " );
+
+ if ( pWeaponName )
+ {
+ pWeaponName++;
+
+ int iWeaponID = AliasToWeaponID(GetTranslatedWeaponAlias(pWeaponName));
+
+ if ( iWeaponID == 0 )
+ continue;
+
+ CCSWeaponInfo *info = GetWeaponInfo( (CSWeaponID)iWeaponID );
+
+ if ( info == NULL )
+ continue;
+
+ if ( CSGameRules()->IsBlackMarket() == false )
+ {
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Removed to avoid clearing of default price when not in black market mode
+ //=============================================================================
+
+ // pButton->SetCurrentPrice( info->GetDefaultPrice() );
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+ }
+ else
+ {
+ int iBargain = info->GetWeaponPrice() - info->GetPrevousPrice();
+
+ pButton->SetCurrentPrice( info->GetWeaponPrice() );
+ pButton->SetPreviousPrice( info->GetPrevousPrice() );
+
+ if ( iBargain < iBestBargain )
+ {
+ iBestBargain = iBargain;
+ pButtonBargain = pButton;
+ }
+ }
+ }
+ }
+
+ if ( pButtonBargain )
+ {
+ pButtonBargain->SetBargainButton( true );
+ }
+}
+
+
+
diff --git a/game/client/cstrike/VGUI/cstrikebuymenu.h b/game/client/cstrike/VGUI/cstrikebuymenu.h
new file mode 100644
index 0000000..a97e07b
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikebuymenu.h
@@ -0,0 +1,102 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSTRIKEBUYMENU_H
+#define CSTRIKEBUYMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/WizardPanel.h>
+
+#include <buymenu.h>
+
+class BuyPresetEditPanel;
+class BuyPresetButton;
+
+namespace vgui
+{
+ class Panel;
+ class Button;
+ class Label;
+}
+
+enum
+{
+ NUM_BUY_PRESET_BUTTONS = 4,
+};
+
+//============================
+// Base CS buy Menu
+//============================
+class CCSBaseBuyMenu : public CBuyMenu
+{
+private:
+ typedef vgui::WizardPanel BaseClass;
+
+public:
+ CCSBaseBuyMenu(IViewPort *pViewPort, const char *subPanelName);
+
+ virtual void ShowPanel( bool bShow );
+ virtual void Paint( void );
+ virtual void SetVisible( bool state );
+
+ void HandleBlackMarket( void );
+
+private:
+ void UpdateBuyPresets( bool showDefaultPanel = false ); ///< Update the Buy Preset buttons and their info panels on the main buy menu
+ vgui::Panel *m_pMainBackground;
+ BuyPresetButton *m_pBuyPresetButtons[NUM_BUY_PRESET_BUTTONS];
+ BuyPresetEditPanel *m_pLoadout;
+ vgui::Label *m_pMoney;
+ int m_lastMoney;
+
+ vgui::EditablePanel *m_pBlackMarket;
+ HFont m_hUnderlineFont;
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+//============================
+// CT main buy Menu
+//============================
+class CCSBuyMenu_CT : public CCSBaseBuyMenu
+{
+private:
+ typedef vgui::WizardPanel BaseClass;
+
+public:
+ CCSBuyMenu_CT(IViewPort *pViewPort);
+
+ virtual const char *GetName( void ) { return PANEL_BUY_CT; }
+};
+
+
+//============================
+// Terrorist main buy Menu
+//============================
+class CCSBuyMenu_TER : public CCSBaseBuyMenu
+{
+private:
+ typedef vgui::WizardPanel BaseClass;
+
+public:
+ CCSBuyMenu_TER(IViewPort *pViewPort);
+
+ virtual const char *GetName( void ) { return PANEL_BUY_TER; }
+};
+
+#endif // CSTRIKEBUYMENU_H
diff --git a/game/client/cstrike/VGUI/cstrikebuysubmenu.h b/game/client/cstrike/VGUI/cstrikebuysubmenu.h
new file mode 100644
index 0000000..ccd0edd
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikebuysubmenu.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSBUYSUBMENU_H
+#define CSBUYSUBMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <buysubmenu.h>
+#include <buymouseoverpanelbutton.h>
+
+using namespace vgui;
+
+class CCSBuySubMenu : public CBuySubMenu
+{
+private:
+ DECLARE_CLASS_SIMPLE(CCSBuySubMenu, CBuySubMenu);
+
+public:
+ CCSBuySubMenu (vgui::Panel *parent,const char *name = "BuySubMenu") : CBuySubMenu( parent, name )
+ {
+ m_backgroundLayoutFinished = false;
+ };
+
+protected:
+
+ virtual void OnThink();
+ void UpdateVestHelmPrice();
+
+ virtual void OnCommand( const char *command );
+
+ MouseOverPanelButton* CreateNewMouseOverPanelButton(EditablePanel * panel)
+ {
+ return new BuyMouseOverPanelButton(this, NULL, panel);
+ }
+
+ CBuySubMenu* CreateNewSubMenu() { return new CCSBuySubMenu( this, "BuySubMenu" ); }
+
+ // Background panel -------------------------------------------------------
+
+ virtual void PerformLayout();
+ virtual void OnSizeChanged(int newWide, int newTall); // called after the size of a panel has been changed
+
+ void HandleBlackMarket( void );
+
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+#endif //CSBUYSUBMENU_H
diff --git a/game/client/cstrike/VGUI/cstrikeclassmenu.cpp b/game/client/cstrike/VGUI/cstrikeclassmenu.cpp
new file mode 100644
index 0000000..374f7ce
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikeclassmenu.cpp
@@ -0,0 +1,272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstrikeclassmenu.h"
+
+#include <KeyValues.h>
+#include <filesystem.h>
+#include <vgui_controls/Button.h>
+#include <vgui/IVGui.h>
+
+#include "hud.h" // for gEngfuncs
+#include "cs_gamerules.h"
+
+using namespace vgui;
+
+
+// ----------------------------------------------------------------------------- //
+// Class image panels. These maintain a list of the class image panels so
+// it can render 3D images into them.
+// ----------------------------------------------------------------------------- //
+
+CUtlVector<CCSClassImagePanel*> g_ClassImagePanels;
+
+
+CCSClassImagePanel::CCSClassImagePanel( vgui::Panel *pParent, const char *pName )
+ : vgui::ImagePanel( pParent, pName )
+{
+ g_ClassImagePanels.AddToTail( this );
+ m_ModelName[0] = 0;
+}
+
+CCSClassImagePanel::~CCSClassImagePanel()
+{
+ g_ClassImagePanels.FindAndRemove( this );
+}
+
+void CCSClassImagePanel::ApplySettings( KeyValues *inResourceData )
+{
+ const char *pName = inResourceData->GetString( "3DModel" );
+ if ( pName )
+ {
+ Q_strncpy( m_ModelName, pName, sizeof( m_ModelName ) );
+ }
+
+ BaseClass::ApplySettings( inResourceData );
+}
+
+
+void CCSClassImagePanel::Paint()
+{
+ BaseClass::Paint();
+}
+
+
+// ----------------------------------------------------------------------------- //
+// CClassMenu_TER
+// ----------------------------------------------------------------------------- //
+
+CClassMenu_TER::CClassMenu_TER(IViewPort *pViewPort) : CClassMenu(pViewPort, PANEL_CLASS_TER)
+{
+ LoadControlSettings( "Resource/UI/ClassMenu_TER.res" );
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+const char *CClassMenu_TER::GetName( void )
+{
+ return PANEL_CLASS_TER;
+}
+
+void CClassMenu_TER::ShowPanel(bool bShow)
+{
+ if ( bShow)
+ {
+ engine->CheckPoint( "ClassMenu" );
+ }
+
+ BaseClass::ShowPanel( bShow );
+
+}
+
+void CClassMenu_TER::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if ( state )
+ {
+ Panel *pAutoButton = FindChildByName( "autoselect_t" );
+ if ( pAutoButton )
+ {
+ pAutoButton->RequestFocus();
+ }
+ }
+}
+
+bool modelExists( const char *search, const CUtlVector< const char * > &names )
+{
+ for ( int i=0; i<names.Count(); ++i )
+ {
+ if ( Q_stristr( names[i], search ) != NULL )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CClassMenu_TER::Update()
+{
+ C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( pLocalPlayer && pLocalPlayer->PlayerClass() >= FIRST_T_CLASS && pLocalPlayer->PlayerClass() <= LAST_T_CLASS )
+ {
+ SetVisibleButton( "CancelButton", true );
+ }
+ else
+ {
+ SetVisibleButton( "CancelButton", false );
+ }
+
+ // if we don't have the new models installed,
+ // turn off the militia and spetsnaz buttons
+ SetVisibleButton( "militia", false );
+}
+
+
+Panel *CClassMenu_TER::CreateControlByName(const char *controlName)
+{
+ if ( Q_stricmp( controlName, "CSClassImagePanel" ) == 0 )
+ {
+ return new CCSClassImagePanel( NULL, controlName );
+ }
+
+ return BaseClass::CreateControlByName( controlName );
+}
+
+
+
+// ----------------------------------------------------------------------------- //
+// CClassMenu_CT
+// ----------------------------------------------------------------------------- //
+
+CClassMenu_CT::CClassMenu_CT(IViewPort *pViewPort) : CClassMenu(pViewPort, PANEL_CLASS_CT)
+{
+ LoadControlSettings( "Resource/UI/ClassMenu_CT.res" );
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+Panel *CClassMenu_CT::CreateControlByName(const char *controlName)
+{
+ if ( Q_stricmp( controlName, "CSClassImagePanel" ) == 0 )
+ {
+ return new CCSClassImagePanel( NULL, controlName );
+ }
+
+ return BaseClass::CreateControlByName( controlName );
+}
+
+const char *CClassMenu_CT::GetName( void )
+{
+ return PANEL_CLASS_CT;
+}
+
+void CClassMenu_CT::ShowPanel(bool bShow)
+{
+ if ( bShow)
+ {
+ engine->CheckPoint( "ClassMenu" );
+ }
+
+ BaseClass::ShowPanel( bShow );
+
+}
+
+void CClassMenu_CT::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if ( state )
+ {
+ Panel *pAutoButton = FindChildByName( "autoselect_ct" );
+ if ( pAutoButton )
+ {
+ pAutoButton->RequestFocus();
+ }
+ }
+}
+
+void CClassMenu_CT::Update()
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( pPlayer && pPlayer->PlayerClass() >= FIRST_CT_CLASS && pPlayer->PlayerClass() <= LAST_CT_CLASS )
+ {
+ SetVisibleButton( "CancelButton", true );
+ }
+ else
+ {
+ SetVisibleButton( "CancelButton", false );
+ }
+
+ // if we don't have the new models installed,
+ // turn off the militia and spetsnaz buttons
+ SetVisibleButton( "spetsnaz", false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CClassMenu_TER::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CClassMenu_TER::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClassMenu_TER::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CClassMenu_CT::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CClassMenu_CT::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClassMenu_CT::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
diff --git a/game/client/cstrike/VGUI/cstrikeclassmenu.h b/game/client/cstrike/VGUI/cstrikeclassmenu.h
new file mode 100644
index 0000000..96a991f
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikeclassmenu.h
@@ -0,0 +1,107 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSCLASSMENU_H
+#define CSCLASSMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <classmenu.h>
+#include <vgui_controls/EditablePanel.h>
+#include <filesystem.h>
+#include <cs_shareddefs.h>
+#include "cbase.h"
+#include "cs_gamerules.h"
+#include "vgui_controls/ImagePanel.h"
+#include "backgroundpanel.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// These are maintained in a list so the renderer can draw a 3D character
+// model on top of them.
+//-----------------------------------------------------------------------------
+
+class CCSClassImagePanel : public vgui::ImagePanel
+{
+public:
+
+ typedef vgui::ImagePanel BaseClass;
+
+ CCSClassImagePanel( vgui::Panel *pParent, const char *pName );
+ virtual ~CCSClassImagePanel();
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void Paint();
+
+
+public:
+ char m_ModelName[128];
+};
+
+extern CUtlVector<CCSClassImagePanel*> g_ClassImagePanels;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the Terrorist class menu
+//-----------------------------------------------------------------------------
+
+class CClassMenu_TER : public CClassMenu
+{
+private:
+ DECLARE_CLASS_SIMPLE( CClassMenu_TER, CClassMenu );
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+
+public:
+ CClassMenu_TER(IViewPort *pViewPort);
+ virtual Panel* CreateControlByName(const char *controlName);
+ const char *GetName( void );
+ void ShowPanel(bool bShow);
+ void Update();
+ virtual void SetVisible(bool state);
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the Counter-Terrorist class menu
+//-----------------------------------------------------------------------------
+
+class CClassMenu_CT : public CClassMenu
+{
+private:
+ DECLARE_CLASS_SIMPLE( CClassMenu_CT, CClassMenu );
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+
+public:
+ CClassMenu_CT(IViewPort *pViewPort);
+ virtual Panel *CreateControlByName(const char *controlName);
+ const char *GetName( void );
+ void ShowPanel(bool bShow);
+ void Update();
+ virtual void SetVisible(bool state);
+};
+
+#endif // CSCLASSMENU_H
diff --git a/game/client/cstrike/VGUI/cstrikeclientscoreboard.cpp b/game/client/cstrike/VGUI/cstrikeclientscoreboard.cpp
new file mode 100644
index 0000000..eb2a652
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikeclientscoreboard.cpp
@@ -0,0 +1,1596 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "cstrikeclientscoreboard.h"
+#include "c_team.h"
+#include "c_cs_playerresource.h"
+#include "c_cs_player.h"
+#include "cs_gamerules.h"
+#include "backgroundpanel.h"
+#include "clientmode.h"
+
+#include <KeyValues.h>
+
+#include <vgui/IScheme.h>
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui_controls/SectionedListPanel.h>
+#include <vgui_controls/ScalableImagePanel.h>
+#include "VGuiMatSurface/IMatSystemSurface.h"
+
+#include "voice_status.h"
+#include "vgui_avatarimage.h"
+
+#include "achievementmgr.h"
+#include "engine/imatchmaking.h"
+
+using namespace vgui;
+
+const int kInvalidImageID = -1;
+const int kMaxMVPCount = 9999;
+const float kScaleMVP = 0.75f; // scale of the MVP star relative to the player name height
+const float kUpdateInterval = 1.0f; // how often the scoreboard refreshes
+const float kTeamScoreMargin = 0.15f; // margin as a ratio of avatar height
+const float kTeamScoreLineLeadingRatio = 0.25f; // padding as a ratio of avatar height
+
+// CT player data colors
+ConVar cl_scoreboard_ct_color_red( "cl_scoreboard_ct_color_red", "150", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player data red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_ct_color_green( "cl_scoreboard_ct_color_green", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player data green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_ct_color_blue( "cl_scoreboard_ct_color_blue", "255", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player data blue channel", true, 0.0f, true, 255.0f );
+
+// T player data colors
+ConVar cl_scoreboard_t_color_red( "cl_scoreboard_t_color_red", "240", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player data red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_t_color_green( "cl_scoreboard_t_color_green", "90", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player data green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_t_color_blue( "cl_scoreboard_t_color_blue", "90", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player data blue channel", true, 0.0f, true, 255.0f );
+
+// Dead player data colors
+ConVar cl_scoreboard_dead_color_red( "cl_scoreboard_dead_color_red", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player data red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_dead_color_green( "cl_scoreboard_dead_color_green", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player data green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_dead_color_blue( "cl_scoreboard_dead_color_blue", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player data blue channel", true, 0.0f, true, 255.0f );
+
+// Clan colors
+ConVar cl_scoreboard_clan_ct_color_red( "cl_scoreboard_clan_ct_color_red", "150", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player clan tag red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_clan_ct_color_green( "cl_scoreboard_clan_ct_color_green", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player clan tag green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_clan_ct_color_blue( "cl_scoreboard_clan_ct_color_blue", "255", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard CT player clan tag blue channel", true, 0.0f, true, 255.0f );
+
+ConVar cl_scoreboard_clan_t_color_red( "cl_scoreboard_clan_t_color_red", "240", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player clan tag red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_clan_t_color_green( "cl_scoreboard_clan_t_color_green", "90", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player clan tag green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_clan_t_color_blue( "cl_scoreboard_clan_t_color_blue", "90", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard T player clan tag blue channel", true, 0.0f, true, 255.0f );
+
+ConVar cl_scoreboard_dead_clan_color_red( "cl_scoreboard_dead_clan_color_red", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player clan tag red channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_dead_clan_color_green( "cl_scoreboard_dead_clan_color_green", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player clan tag green channel", true, 0.0f, true, 255.0f );
+ConVar cl_scoreboard_dead_clan_color_blue( "cl_scoreboard_dead_clan_color_blue", "125", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Scoreboard dead player clan tag blue channel", true, 0.0f, true, 255.0f );
+
+
+// [tj] These ConVars are defined at various places in the global scope. Just declaring them here so we can use them
+extern ConVar mp_winlimit;
+extern ConVar mp_maxrounds;
+extern ConVar mp_timelimit;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSClientScoreBoardDialog::CCSClientScoreBoardDialog( IViewPort *pViewPort ) : CClientScoreBoardDialog( pViewPort ),
+ m_DeadPlayerDataColor( 125, 125, 125, 125 ),
+ m_PlayerDataBgColor( 0, 0, 0, 0 ),
+ m_DeadPlayerClanColor( 125, 125, 125, 125 )
+{
+ m_teamDisplayT.playerDataColor = Color( 240, 90, 90, 255 );
+ m_teamDisplayT.playerClanColor = Color( 240, 90, 90, 255 );
+
+ m_teamDisplayCT.playerDataColor = Color( 150, 200, 255, 255 );
+ m_teamDisplayCT.playerClanColor = Color( 150, 200, 255, 255 );
+
+ m_iImageDead = kInvalidImageID;
+ m_iImageDominated = kInvalidImageID;
+ m_iImageNemesis = kInvalidImageID;
+ m_iImageBomb = kInvalidImageID;
+ m_iImageVIP = kInvalidImageID;
+ m_iImageFriend = kInvalidImageID;
+ m_iImageNemesisDead = kInvalidImageID;
+ m_iImageDominationDead = kInvalidImageID;
+
+ m_pWinConditionLabel = new Label( this, "WinConditionLabel", "" );
+ m_pClockLabel = new Label( this, "Icon_Clock", "" );
+
+ m_pLabelMapName = new Label( this, "MapName", "" );
+ m_pServerLabel = new Label( this, "ServerNameLabel", "" );
+
+ ListenForGameEvent( "server_spawn" );
+ ListenForGameEvent( "game_newmap" );
+ ListenForGameEvent( "match_end_conditions" );
+ ListenForGameEvent( "cs_win_panel_match" );
+
+ SetDialogVariable( "server", "" );
+ SetVisible( false );
+ SetProportional(true);
+ SetPaintBorderEnabled(false);
+ SetScheme( "ClientScheme" );
+
+ // [pfreese] Make the scoreboard a popup so it renders over the chat interface (which is also a popup). Hacky.
+ MakePopup();
+
+ m_listItemFont = NULL;
+
+ m_LocalPlayerItemID = -1;
+ m_iImageMVP = -1;
+
+ m_gameOver = false;
+
+ if ( g_pClientMode &&
+ g_pClientMode->GetMapName() )
+ {
+ V_wcsncpy( m_pMapName, g_pClientMode->GetMapName(), sizeof( m_pMapName ) );
+ SetDialogVariable( "mapname", m_pMapName );
+ m_pLabelMapName->SetVisible( true );
+ }
+
+ SetKeyBoardInputEnabled( true );
+
+ for ( int i = 0; i < cMaxScoreLines; ++i )
+ {
+ PlayerDisplay* pPlayerDisplay;
+
+ pPlayerDisplay = &m_teamDisplayCT.playerDisplay[i];
+ pPlayerDisplay->pClanLabel = NULL;
+ pPlayerDisplay->pNameLabel = NULL;
+ pPlayerDisplay->pScoreLabel = NULL;
+ pPlayerDisplay->pDeathsLabel = NULL;
+ pPlayerDisplay->pPingLabel = NULL;
+ pPlayerDisplay->pMVPCountLabel = NULL;
+ pPlayerDisplay->pAvatar = NULL;
+ pPlayerDisplay->pStatusImage = NULL;
+ pPlayerDisplay->pMVPImage = NULL;
+ pPlayerDisplay->pSelect = NULL;
+
+ pPlayerDisplay = &m_teamDisplayT.playerDisplay[i];
+ pPlayerDisplay->pClanLabel = NULL;
+ pPlayerDisplay->pNameLabel = NULL;
+ pPlayerDisplay->pScoreLabel = NULL;
+ pPlayerDisplay->pDeathsLabel = NULL;
+ pPlayerDisplay->pPingLabel = NULL;
+ pPlayerDisplay->pMVPCountLabel = NULL;
+ pPlayerDisplay->pAvatar = NULL;
+ pPlayerDisplay->pStatusImage = NULL;
+ pPlayerDisplay->pMVPImage = NULL;
+ pPlayerDisplay->pSelect = NULL;
+ }
+
+ m_pServerName[0] = L'\0';
+ m_pStatsEnabled[0] = L'\0';
+ m_pStatsDisabled[0] = L'\0';
+
+ m_MVPXOffset = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCSClientScoreBoardDialog::~CCSClientScoreBoardDialog()
+{
+ for (int i = 0; i < cMaxScoreLines; ++i)
+ {
+ PlayerDisplay* pPlayerDisplay;
+
+ pPlayerDisplay = &m_teamDisplayCT.playerDisplay[i];
+ delete pPlayerDisplay->pClanLabel;
+ delete pPlayerDisplay->pNameLabel;
+ delete pPlayerDisplay->pScoreLabel;
+ delete pPlayerDisplay->pDeathsLabel;
+ delete pPlayerDisplay->pPingLabel;
+ delete pPlayerDisplay->pMVPCountLabel;
+ delete pPlayerDisplay->pAvatar;
+ delete pPlayerDisplay->pStatusImage;
+ delete pPlayerDisplay->pMVPImage;
+ delete pPlayerDisplay->pSelect;
+
+ pPlayerDisplay = &m_teamDisplayT.playerDisplay[i];
+ delete pPlayerDisplay->pClanLabel;
+ delete pPlayerDisplay->pNameLabel;
+ delete pPlayerDisplay->pScoreLabel;
+ delete pPlayerDisplay->pDeathsLabel;
+ delete pPlayerDisplay->pPingLabel;
+ delete pPlayerDisplay->pMVPCountLabel;
+ delete pPlayerDisplay->pAvatar;
+ delete pPlayerDisplay->pStatusImage;
+ delete pPlayerDisplay->pMVPImage;
+ delete pPlayerDisplay->pSelect;
+ }
+}
+
+const wchar_t *LocalizeFindSafe( const char *pTokenName )
+{
+ const wchar_t *pStr = g_pVGuiLocalize->Find( pTokenName );
+ return pStr ? pStr : L"\0";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Apply scheme settings
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ //
+ // [smessick] Note: ApplySchemeSettings is called multiple times for the scoreboard.
+ // Therefore, we must make sure to delete previously allocated items.
+ //
+
+ LoadControlSettings( "Resource/UI/scoreboard.res" );
+
+ //Just used for a background alpha value. 50% opacity
+ m_listItemFont = pScheme->GetFont( "ScoreboardBody_1", IsProportional() );
+ m_listItemFontSmaller = pScheme->GetFont( "ScoreboardBody_2", IsProportional() );
+ m_listItemFontSmallest = pScheme->GetFont( "ScoreboardBody_3", IsProportional() );
+ m_MVPFont = pScheme->GetFont( "ScoreboardMVP", IsProportional() );
+
+ SetBgColor( Color( 0, 0, 0, 0 ) );
+ SetBorder( pScheme->GetBorder( "BaseBorder" ) );
+
+ // turn off the default player list since we have our own
+ if ( m_pPlayerList )
+ {
+ m_pPlayerList->SetVisible( false );
+ }
+
+ // Set the player colors from the convars.
+ UpdatePlayerColors();
+
+ m_MVPXOffset = scheme()->GetProportionalScaledValueEx( GetScheme(), 2 );
+
+ SetupTeamDisplay( m_teamDisplayCT, "CT" );
+ SetupTeamDisplay( m_teamDisplayT, "T" );
+
+ // Set the server name (in the case of a resolution change).
+ if ( m_pServerName[0] == L'\0' &&
+ g_pClientMode->GetServerName() != NULL )
+ {
+ V_wcsncpy( m_pServerName, g_pClientMode->GetServerName(), sizeof( m_pServerName ) );
+ }
+
+ // Cache the stats enabled string.
+ if ( m_pStatsEnabled[0] == L'\0' )
+ {
+ V_wcsncpy( m_pStatsEnabled, LocalizeFindSafe( "#Cstrike_Scoreboard_StatsEnabled" ), sizeof( m_pStatsEnabled ) );
+ }
+
+ // Cache the stats disabled string.
+ if ( m_pStatsDisabled[0] == L'\0' )
+ {
+ V_wcsncpy( m_pStatsDisabled, LocalizeFindSafe( "#Cstrike_Scoreboard_StatsDisabled" ), sizeof( m_pStatsDisabled ) );
+ }
+
+ SetVisible( false );
+}
+
+
+void CCSClientScoreBoardDialog::SetupTeamDisplay( TeamDisplayInfo& teamDisplay, const char* szTeamPrefix )
+{
+ const int selectMargin = scheme()->GetProportionalScaledValueEx( GetScheme(), 1 );
+ const int mvpLabelWidth = scheme()->GetProportionalScaledValueEx( GetScheme(), 20 );
+ const int mvpLabelYOffset = scheme()->GetProportionalScaledValueEx( GetScheme(), 2 );
+
+ char tmpName[32];
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerArea", szTeamPrefix );
+ Panel *pPlayerArea = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerAvatar0", szTeamPrefix );
+ Panel *pPlayerAvatar0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerClan0", szTeamPrefix );
+ Panel *pPlayerClan0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerName0", szTeamPrefix );
+ Panel *pPlayerName0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerStatus0", szTeamPrefix );
+ Panel *pPlayerStatus0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerScore0", szTeamPrefix );
+ Panel *pPlayerScore0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerDeaths0", szTeamPrefix );
+ Panel *pPlayerDeaths0 = FindChildByName( tmpName );
+
+ V_snprintf( tmpName, sizeof(tmpName), "%sPlayerLatency0", szTeamPrefix );
+ Panel *pPlayerLatency0 = FindChildByName( tmpName );
+
+ // Get the bounds of the player area.
+ int playerX = 0;
+ int playerY = 0;
+ int playerWide = 0;
+ int playerTall = 0;
+ if ( pPlayerArea )
+ pPlayerArea->GetBounds( playerX, playerY, playerWide, playerTall );
+
+ // determine the line height needed
+ int x, y, wide, tall;
+ teamDisplay.scoreAreaLineHeight = 0;
+ teamDisplay.scoreAreaMinX = INT_MAX;
+ teamDisplay.scoreAreaMaxX = INT_MIN;
+
+ if ( pPlayerAvatar0 != NULL )
+ {
+ pPlayerAvatar0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerClan0 != NULL )
+ {
+ pPlayerClan0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerName0 != NULL )
+ {
+ pPlayerName0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerScore0 != NULL )
+ {
+ pPlayerScore0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerDeaths0 != NULL )
+ {
+ pPlayerDeaths0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerLatency0 != NULL )
+ {
+ pPlayerLatency0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+ if ( pPlayerStatus0 != NULL )
+ {
+ pPlayerStatus0->GetBounds( x, y, wide, tall );
+ teamDisplay.scoreAreaLineHeight = MAX( tall, teamDisplay.scoreAreaLineHeight );
+ teamDisplay.scoreAreaMinX = MIN( teamDisplay.scoreAreaMinX, x );
+ teamDisplay.scoreAreaMaxX = MAX( teamDisplay.scoreAreaMaxX, x + wide );
+ }
+
+ int marginY = RoundFloatToInt(teamDisplay.scoreAreaLineHeight * kTeamScoreMargin);
+
+ teamDisplay.scoreAreaInnerHeight = playerTall - 2 * marginY;
+ teamDisplay.scoreAreaLinePreferredLeading = RoundFloatToInt(teamDisplay.scoreAreaLineHeight * kTeamScoreLineLeadingRatio);
+ teamDisplay.scoreAreaStartY = playerY + marginY;
+ teamDisplay.maxPlayersVisible = MIN(cMaxScoreLines, teamDisplay.scoreAreaInnerHeight / teamDisplay.scoreAreaLineHeight);
+
+ // Calculate the starting point for player data.
+ int startY = teamDisplay.scoreAreaStartY;
+ int spacingY = teamDisplay.scoreAreaLineHeight + teamDisplay.scoreAreaLinePreferredLeading;
+
+ for ( int i = 0; i < cMaxScoreLines; ++i, startY += spacingY )
+ {
+ PlayerDisplay& playerDisplay = teamDisplay.playerDisplay[i];
+
+ int wide = 0;
+ int tall = 0;
+ int x = 0;
+ int y = 0;
+
+ // avatar
+ if ( pPlayerAvatar0 != NULL )
+ {
+ pPlayerAvatar0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playeravatar%d", szTeamPrefix, i );
+ delete playerDisplay.pAvatar;
+ playerDisplay.pAvatar = (CAvatarImagePanel*)SETUP_PANEL( new CAvatarImagePanel( this, tmpName ) );
+ playerDisplay.pAvatar->SetBounds( x, startY, wide, tall );
+ playerDisplay.pAvatar->SetDefaultAvatar( scheme()->GetImage( &teamDisplay == &m_teamDisplayCT ? CSTRIKE_DEFAULT_CT_AVATAR : CSTRIKE_DEFAULT_T_AVATAR, true ) );
+ playerDisplay.pAvatar->SetShouldDrawFriendIcon( false );
+ playerDisplay.pAvatar->SetShouldScaleImage( true );
+ playerDisplay.pAvatar->SetVisible( false );
+ }
+
+ // clan
+ if ( pPlayerClan0 != NULL )
+ {
+ pPlayerClan0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playerclan%d", szTeamPrefix, i );
+ delete playerDisplay.pClanLabel;
+ playerDisplay.pClanLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, tmpName ) );
+ playerDisplay.pClanLabel->SetFont( m_listItemFont );
+ playerDisplay.pClanLabel->SetBounds( x, startY, wide, tall );
+ playerDisplay.pClanLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pClanLabel->SetFgColor( m_teamDisplayCT.playerClanColor );
+ playerDisplay.pClanLabel->SetContentAlignment( Label::a_east );
+ playerDisplay.pClanLabel->SetVisible( false );
+ }
+
+ // name
+ if ( pPlayerName0 != NULL )
+ {
+ pPlayerName0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playername%d", szTeamPrefix, i );
+ delete playerDisplay.pNameLabel;
+ playerDisplay.pNameLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, tmpName ) );
+ playerDisplay.pNameLabel->SetFont( m_listItemFont );
+ playerDisplay.pNameLabel->SetBounds( x, startY, wide, tall);
+ playerDisplay.pNameLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pNameLabel->SetFgColor( m_teamDisplayCT.playerDataColor );
+ playerDisplay.pNameLabel->SetContentAlignment( Label::a_west );
+ playerDisplay.pNameLabel->SetVisible( false );
+
+ // mvp
+ int wideMVP = RoundFloatToInt(teamDisplay.scoreAreaLineHeight * kScaleMVP);
+ int tallMVP = RoundFloatToInt(teamDisplay.scoreAreaLineHeight * kScaleMVP);
+ int yMVP = ( teamDisplay.scoreAreaLineHeight - tallMVP ) / 2;
+
+ V_snprintf( tmpName, 32, "_%s_mvp%d", szTeamPrefix, i );
+ delete playerDisplay.pMVPImage;
+ playerDisplay.pMVPImage = (ImagePanel*)SETUP_PANEL( new ImagePanel( this, tmpName ) );
+ playerDisplay.pMVPImage->SetBounds( x, startY + yMVP, wideMVP, tallMVP );
+ playerDisplay.pMVPImage->SetImage( "../hud/scoreboard_mvp" );
+ playerDisplay.pMVPImage->SetShouldScaleImage( true );
+ playerDisplay.pMVPImage->SetVisible( false );
+
+ // mvp count
+ V_snprintf( tmpName, 32, "_%s_mvpcount%d", szTeamPrefix, i );
+ delete playerDisplay.pMVPCountLabel;
+ playerDisplay.pMVPCountLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, "" ) );
+ playerDisplay.pMVPCountLabel->SetFont( m_MVPFont );
+ playerDisplay.pMVPCountLabel->SetBounds( 0, -mvpLabelYOffset, mvpLabelWidth, tallMVP );
+ playerDisplay.pMVPCountLabel->SetVisible( false );
+
+ // Pin to the mvp image.
+ V_snprintf( tmpName, 32, "_%s_mvp%d", szTeamPrefix, i );
+ playerDisplay.pMVPCountLabel->PinToSibling( tmpName, PIN_CENTER_LEFT, PIN_CENTER_RIGHT );
+ }
+
+ // score
+ if ( pPlayerScore0 != NULL )
+ {
+ pPlayerScore0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playerscore%d", szTeamPrefix, i );
+ delete playerDisplay.pScoreLabel;
+ playerDisplay.pScoreLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, "" ) );
+ playerDisplay.pScoreLabel->SetFont( m_listItemFont );
+ playerDisplay.pScoreLabel->SetBounds( x, startY, wide, tall );
+ playerDisplay.pScoreLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pScoreLabel->SetFgColor( m_teamDisplayCT.playerDataColor );
+ playerDisplay.pScoreLabel->SetContentAlignment( Label::a_center );
+ playerDisplay.pScoreLabel->SetVisible( false );
+ }
+
+ // deaths
+ if ( pPlayerDeaths0 != NULL )
+ {
+ pPlayerDeaths0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playerdeaths%d", szTeamPrefix, i );
+ delete playerDisplay.pDeathsLabel;
+ playerDisplay.pDeathsLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, "" ) );
+ playerDisplay.pDeathsLabel->SetFont( m_listItemFont );
+ playerDisplay.pDeathsLabel->SetBounds( x, startY, wide, tall );
+ playerDisplay.pDeathsLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pDeathsLabel->SetFgColor( m_teamDisplayCT.playerDataColor );
+ playerDisplay.pDeathsLabel->SetContentAlignment( Label::a_center );
+ playerDisplay.pDeathsLabel->SetVisible( false );
+ }
+
+ // latency
+ if ( pPlayerLatency0 != NULL )
+ {
+ pPlayerLatency0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playerping%d", szTeamPrefix, i );
+ delete playerDisplay.pPingLabel;
+ playerDisplay.pPingLabel = (Label*)SETUP_PANEL( new Label( this, tmpName, "" ) );
+ playerDisplay.pPingLabel->SetFont( m_listItemFont );
+ playerDisplay.pPingLabel->SetBounds( x, startY, wide, tall );
+ playerDisplay.pPingLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pPingLabel->SetFgColor( m_teamDisplayCT.playerDataColor );
+ playerDisplay.pPingLabel->SetContentAlignment( Label::a_center );
+ playerDisplay.pPingLabel->SetVisible( false );
+ }
+
+ // status
+ if ( pPlayerStatus0 != NULL )
+ {
+ pPlayerStatus0->GetBounds( x, y, wide, tall );
+ V_snprintf( tmpName, 32, "_%s_playerstatus%d", szTeamPrefix, i );
+ delete playerDisplay.pStatusImage;
+ playerDisplay.pStatusImage = (ImagePanel*)SETUP_PANEL( new ImagePanel( this, tmpName ) );
+ playerDisplay.pStatusImage->SetBounds( x, startY, wide, tall );
+ playerDisplay.pStatusImage->SetImage( "../hud/scoreboard_dead" );
+ playerDisplay.pStatusImage->SetShouldScaleImage( true );
+ playerDisplay.pStatusImage->SetVisible( false );
+ }
+
+ // select
+ {
+ int x1 = teamDisplay.scoreAreaMinX - selectMargin;
+ int y1 = startY - selectMargin;
+ int x2 = teamDisplay.scoreAreaMaxX + selectMargin;
+ int y2 = startY + teamDisplay.scoreAreaLineHeight + selectMargin;
+
+ V_snprintf( tmpName, 32, "_%s_playerselect%d", szTeamPrefix, i );
+ delete playerDisplay.pSelect;
+ playerDisplay.pSelect = (ImagePanel*)SETUP_PANEL( new ImagePanel( this, tmpName ) );
+ playerDisplay.pSelect->SetBounds( x1, y1, x2 - x1, y2 - y1 );
+ playerDisplay.pSelect->SetImage( "../vgui/scoreboard/scoreboard-select" );
+ playerDisplay.pSelect->SetShouldScaleImage( true );
+ playerDisplay.pSelect->SetVisible( false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Used for sorting players
+//-----------------------------------------------------------------------------
+int CCSClientScoreBoardDialog::PlayerSortFunction( PlayerScoreInfo* const* pLeft, PlayerScoreInfo* const* pRight )
+{
+ // a return value < 0 puts pLeft earlier in the list, > 0 puts pRight earlier
+ const PlayerScoreInfo* pPlayer1 = *pLeft;
+ const PlayerScoreInfo* pPlayer2 = *pRight;
+ Assert( pPlayer1 && pPlayer2 );
+
+ // bail out early if either player is an empty slot, i.e. has a player index of -1
+ if( pPlayer1->playerIndex == -1 )
+ return 1;
+ if( pPlayer2->playerIndex == -1 )
+ return -1;
+
+ // first compare scores
+ if ( pPlayer1->frags > pPlayer2->frags )
+ return -1;
+ if ( pPlayer1->frags < pPlayer2->frags )
+ return 1;
+
+ // second compare deaths
+ if ( pPlayer1->deaths > pPlayer2->deaths )
+ return 1;
+ if ( pPlayer1->deaths < pPlayer2->deaths )
+ return -1;
+
+ // if score and deaths are the same, use player index to get deterministic sort
+ if ( pPlayer1->playerIndex < pPlayer2->playerIndex )
+ return -1;
+ else
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the dialog
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::Update()
+{
+ if ( m_pServerLabel )
+ {
+ m_pServerLabel->SetText( m_pServerName );
+ }
+
+ // Update the stats status.
+ CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr*>( engine->GetAchievementMgr() );
+ if ( pAchievementMgr != NULL &&
+ pAchievementMgr->CheckAchievementsEnabled() )
+ {
+ SetDialogVariable( "statsstatus", m_pStatsEnabled );
+ }
+ else
+ {
+ SetDialogVariable( "statsstatus", m_pStatsDisabled );
+ }
+
+ UpdateTeamInfo();
+ UpdatePlayerList();
+ UpdateSpectatorList();
+ UpdateHLTVList();
+ UpdateMatchEndText();
+ UpdateMvpElements();
+
+ // update every second
+ m_fNextUpdateTime = gpGlobals->curtime + kUpdateInterval;
+
+ // Catch the case where we call ShowPanel before ApplySchemeSettings, eg when going from windowed <-> fullscreen
+ if ( m_pImageList == NULL )
+ {
+ InvalidateLayout( true, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates information about teams
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdateTeamInfo()
+{
+ if ( g_PR == NULL )
+ {
+ return;
+ }
+
+ // update the team sections in the scoreboard
+ for ( int teamIndex = TEAM_TERRORIST; teamIndex <= TEAM_CT; teamIndex++ )
+ {
+ wchar_t *teamName = NULL;
+ C_Team *team = GetGlobalTeam( teamIndex );
+ if ( team )
+ {
+ // choose dialog variables to set depending on team
+ const char *pDialogVarTeamName = NULL;
+ const char *pDialogVarAliveCount = NULL;
+ const char *pDialogVarTeamScore = NULL;
+ switch ( teamIndex )
+ {
+ case TEAM_TERRORIST:
+ teamName = g_pVGuiLocalize->Find( "#Cstrike_Team_T" );
+ pDialogVarTeamName = "t_teamname";
+ pDialogVarAliveCount = "t_alivecount";
+ pDialogVarTeamScore = "t_totalteamscore";
+ break;
+ case TEAM_CT:
+ teamName = g_pVGuiLocalize->Find( "#Cstrike_Team_CT" );
+ pDialogVarTeamName = "ct_teamname";
+ pDialogVarAliveCount = "ct_alivecount";
+ pDialogVarTeamScore = "ct_totalteamscore";
+ break;
+ default:
+ Assert( false );
+ break;
+ }
+
+ // Set the team name if it hasn't been set.
+ wchar_t name[64];
+ if ( !teamName && team && team->Get_Name() != NULL )
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode( team->Get_Name(), name, sizeof( name ) );
+ teamName = name;
+ }
+
+ // Count the players on the team.
+ int numPlayers = 0;
+ int numAlive = 0;
+ for ( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ )
+ {
+ if ( g_PR->IsConnected( playerIndex ) && g_PR->GetTeam( playerIndex ) == teamIndex )
+ {
+ numPlayers++;
+ if ( g_PR->IsAlive( playerIndex ) )
+ {
+ ++numAlive;
+ }
+ }
+ }
+
+ SetDialogVariable( pDialogVarTeamName, teamName );
+
+ // Team score
+ wchar_t wNumScore[16];
+ V_snwprintf( wNumScore, ARRAYSIZE( wNumScore ), L"%i", team->Get_Score() );
+ SetDialogVariable( pDialogVarTeamScore, wNumScore );
+
+ // Number of alive players
+ wchar_t numAliveString[32];
+ V_snwprintf( numAliveString, ARRAYSIZE( numAliveString ), L"%i / %i", numAlive, numPlayers);
+ SetDialogVariable( pDialogVarAliveCount, numAliveString );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper to shrink font size when a string gets too long for its label
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::AdjustFontToFit( const char *pString, vgui::Label *pLabel )
+{
+ if ( !pString || !pLabel )
+ return;
+
+ int len = Q_strlen( pString );
+ if ( !len )
+ return;
+
+ int arraySize = len + 1;
+ wchar_t *pWideString = new wchar_t[arraySize];
+ V_UTF8ToUnicode( pString, pWideString, (arraySize * sizeof(wchar_t)) );
+
+ int stringWidth, stringHeight;
+ g_pMatSystemSurface->GetTextSize( m_listItemFont, pWideString, stringWidth, stringHeight );
+
+ int labelWidth = pLabel->GetWide();
+ if ( stringWidth <= labelWidth )
+ {
+ pLabel->SetFont( m_listItemFont );
+ }
+ else
+ {
+ g_pMatSystemSurface->GetTextSize( m_listItemFontSmaller, pWideString, stringWidth, stringHeight );
+ if ( stringWidth <= labelWidth )
+ {
+ pLabel->SetFont( m_listItemFontSmaller );
+ }
+ else
+ {
+ pLabel->SetFont(m_listItemFontSmallest);
+ }
+ }
+ delete [] pWideString;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the player list
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdatePlayerList()
+{
+ m_teamDisplayT.playerScores.PurgeAndDeleteElements();
+ m_teamDisplayCT.playerScores.PurgeAndDeleteElements();
+
+ C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( !pLocalPlayer )
+ return;
+
+ // Set the player colors from the convars.
+ UpdatePlayerColors();
+
+ for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ )
+ {
+ if( g_PR->IsConnected( playerIndex ) )
+ {
+ PlayerScoreInfo* playerScoreInfo = new PlayerScoreInfo;
+ if ( !GetPlayerScoreInfo( playerIndex, *playerScoreInfo ) )
+ {
+ delete playerScoreInfo;
+ continue;
+ }
+
+ if ( g_PR->GetTeam( playerIndex ) == TEAM_TERRORIST )
+ {
+ m_teamDisplayT.playerScores.AddToTail(playerScoreInfo);
+ }
+ else if ( g_PR->GetTeam( playerIndex ) == TEAM_CT )
+ {
+ m_teamDisplayCT.playerScores.AddToTail(playerScoreInfo);
+ }
+ else
+ {
+ // [mhansen] make sure we don't leak here
+ delete playerScoreInfo;
+ }
+ }
+ }
+
+ // Sort the lists of players
+ m_teamDisplayT.playerScores.Sort(PlayerSortFunction);
+ m_teamDisplayCT.playerScores.Sort(PlayerSortFunction);
+
+ // Force the local player to be visible when he is below the visible portion of the sorted list
+ if ( pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST )
+ ForceLocalPlayerVisible(m_teamDisplayT);
+ else if ( pLocalPlayer->GetTeamNumber() == TEAM_CT )
+ ForceLocalPlayerVisible(m_teamDisplayCT);
+
+ UpdateTeamPlayerDisplay(m_teamDisplayT);
+ UpdateTeamPlayerDisplay(m_teamDisplayCT);
+}
+
+void CCSClientScoreBoardDialog::UpdateTeamPlayerDisplay( TeamDisplayInfo& teamDisplay )
+{
+ const int selectMargin = scheme()->GetProportionalScaledValueEx( GetScheme(), 1 );
+
+ C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR );
+ if ( !cs_PR )
+ return;
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+
+ int maxTeamSize = MAX(m_teamDisplayT.playerScores.Count(), m_teamDisplayCT.playerScores.Count());
+
+ // adjust spacing
+ int leadingAvailable = teamDisplay.scoreAreaInnerHeight - maxTeamSize * teamDisplay.scoreAreaLineHeight;
+ int leading = 0;
+ if ( maxTeamSize > 1 ) // only makes sense if we have more than one player
+ {
+ leading = clamp(leadingAvailable / (maxTeamSize - 1), 0, teamDisplay.scoreAreaLinePreferredLeading);
+ }
+ int spacingY = teamDisplay.scoreAreaLineHeight + leading;
+
+ // temp values for updating just the y position of elements
+ int xPos, yPos;
+
+ int i = 0;
+ int startY = teamDisplay.scoreAreaStartY;
+ for ( i = 0; i < MIN( cMaxScoreLines, teamDisplay.playerScores.Count() ); ++i, startY += spacingY )
+ {
+ if ( startY + teamDisplay.scoreAreaLineHeight > teamDisplay.scoreAreaStartY + teamDisplay.scoreAreaInnerHeight )
+ break;
+
+ PlayerDisplay& playerDisplay = teamDisplay.playerDisplay[i];
+
+ const PlayerScoreInfo* pPlayerScore = teamDisplay.playerScores[i];
+ if ( pPlayerScore )
+ {
+ int playerIndex = pPlayerScore->playerIndex;
+
+ const char* pUTF8Name = pPlayerScore->szName;
+
+// int bufsize;
+// if ( g_PR->IsFakePlayer( playerIndex ) )
+// bufsize = strlen( oldName ) * 2 + 14 + 1;
+// else
+// bufsize = strlen( oldName ) * 2 + 1;
+//
+// char *newName = (char *)_alloca( bufsize );
+// UTIL_MakeSafeName( oldName, newName, bufsize );
+
+ if ( pUTF8Name != NULL && V_strlen( pUTF8Name ) > 0 )
+ {
+ bool isAlive = cs_PR->IsAlive( playerIndex );
+ Color fgColor = ( isAlive ? teamDisplay.playerDataColor : m_DeadPlayerDataColor );
+ Color fgClanColor = ( isAlive ? teamDisplay.playerClanColor : m_DeadPlayerClanColor );
+
+ if ( playerDisplay.pNameLabel != NULL )
+ {
+ AdjustFontToFit( pUTF8Name, playerDisplay.pNameLabel );
+
+ playerDisplay.pNameLabel->SetVisible( true );
+ playerDisplay.pNameLabel->SetText( pUTF8Name );
+ playerDisplay.pNameLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pNameLabel->SetFgColor( fgColor );
+ playerDisplay.pNameLabel->GetPos(xPos, yPos);
+ playerDisplay.pNameLabel->SetPos(xPos, startY);
+
+ int tallMVP = RoundFloatToInt(teamDisplay.scoreAreaLineHeight * kScaleMVP);
+ int yMVP = ( teamDisplay.scoreAreaLineHeight - tallMVP ) / 2;
+ playerDisplay.pMVPImage->SetPos( xPos, startY + yMVP);
+ }
+
+ if ( playerDisplay.pClanLabel != NULL )
+ {
+ const char* pUTF8Clan = pPlayerScore->szClanTag;
+ AdjustFontToFit( pUTF8Clan, playerDisplay.pClanLabel );
+
+ playerDisplay.pClanLabel->SetVisible( true );
+ playerDisplay.pClanLabel->SetText( pUTF8Clan );
+ playerDisplay.pClanLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pClanLabel->SetFgColor( fgClanColor );
+ playerDisplay.pClanLabel->GetPos(xPos, yPos);
+ playerDisplay.pClanLabel->SetPos(xPos, startY);
+ }
+
+ char tmpbuf[16];
+
+ if ( playerDisplay.pScoreLabel != NULL )
+ {
+ Q_snprintf( tmpbuf, sizeof( tmpbuf ), "%d", pPlayerScore->frags);
+ playerDisplay.pScoreLabel->SetVisible( true );
+ playerDisplay.pScoreLabel->SetText( tmpbuf );
+ playerDisplay.pScoreLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pScoreLabel->SetFgColor( fgColor );
+ playerDisplay.pScoreLabel->GetPos(xPos, yPos);
+ playerDisplay.pScoreLabel->SetPos(xPos, startY);
+ }
+
+ if ( playerDisplay.pDeathsLabel != NULL )
+ {
+ Q_snprintf( tmpbuf, sizeof( tmpbuf ), "%d", pPlayerScore->deaths);
+ playerDisplay.pDeathsLabel->SetVisible( true );
+ playerDisplay.pDeathsLabel->SetText( tmpbuf );
+ playerDisplay.pDeathsLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pDeathsLabel->SetFgColor( fgColor );
+ playerDisplay.pDeathsLabel->GetPos(xPos, yPos);
+ playerDisplay.pDeathsLabel->SetPos(xPos, startY);
+
+ }
+
+ if ( playerDisplay.pPingLabel != NULL )
+ {
+ if ( pPlayerScore->ping >= 0 )
+ Q_snprintf( tmpbuf, sizeof( tmpbuf ), "%d", pPlayerScore->ping);
+ else
+ Q_strcpy( tmpbuf, "BOT");
+
+ playerDisplay.pPingLabel->SetVisible( true );
+ playerDisplay.pPingLabel->SetText( tmpbuf );
+ playerDisplay.pPingLabel->SetBgColor( m_PlayerDataBgColor );
+ playerDisplay.pPingLabel->SetFgColor( fgColor );
+ playerDisplay.pPingLabel->GetPos(xPos, yPos);
+ playerDisplay.pPingLabel->SetPos(xPos, startY);
+
+ }
+ }
+
+ if ( playerDisplay.pStatusImage != NULL )
+ {
+ if ( pPlayerScore->szStatus == NULL )
+ {
+ playerDisplay.pStatusImage->SetVisible( false );
+ }
+ else
+ {
+ playerDisplay.pStatusImage->SetVisible( true );
+ playerDisplay.pStatusImage->SetImage( pPlayerScore->szStatus );
+ playerDisplay.pStatusImage->GetPos(xPos, yPos);
+ playerDisplay.pStatusImage->SetPos(xPos, startY);
+ playerDisplay.pStatusImage->SetDrawColor(pPlayerScore->bStatusPlayerColor ? teamDisplay.playerDataColor : COLOR_WHITE);
+ }
+ }
+
+ if ( playerDisplay.pAvatar != NULL )
+ {
+ playerDisplay.pAvatar->SetVisible( true );
+ playerDisplay.pAvatar->SetPlayer( playerIndex, k_EAvatarSize32x32 );
+ playerDisplay.pAvatar->GetPos(xPos, yPos);
+ playerDisplay.pAvatar->SetPos(xPos, startY);
+ }
+
+ if ( playerDisplay.pSelect != NULL )
+ {
+ playerDisplay.pSelect->SetVisible( pPlayerScore->playerIndex == iLocalPlayerIndex );
+ playerDisplay.pSelect->SetPos(teamDisplay.scoreAreaMinX - selectMargin, startY - selectMargin);
+ }
+ }
+ }
+
+ // set any remaining entries to non-visible
+ for ( ; i < cMaxScoreLines; ++i )
+ {
+ PlayerDisplay& playerDisplay = teamDisplay.playerDisplay[i];
+
+ if ( playerDisplay.pClanLabel != NULL )
+ playerDisplay.pClanLabel->SetVisible(false);
+
+ if ( playerDisplay.pNameLabel != NULL )
+ playerDisplay.pNameLabel->SetVisible(false);
+
+ if ( playerDisplay.pScoreLabel != NULL )
+ playerDisplay.pScoreLabel->SetVisible(false);
+
+ if ( playerDisplay.pDeathsLabel != NULL )
+ playerDisplay.pDeathsLabel->SetVisible(false);
+
+ if ( playerDisplay.pPingLabel != NULL )
+ playerDisplay.pPingLabel->SetVisible(false);
+
+ if ( playerDisplay.pStatusImage != NULL )
+ playerDisplay.pStatusImage->SetVisible(false);
+
+ if ( playerDisplay.pAvatar != NULL )
+ playerDisplay.pAvatar->SetVisible( false );
+
+ if ( playerDisplay.pMVPImage != NULL )
+ playerDisplay.pMVPImage->SetVisible( false );
+
+ if ( playerDisplay.pMVPCountLabel != NULL )
+ playerDisplay.pMVPCountLabel->SetVisible( false );
+
+ if ( playerDisplay.pSelect != NULL )
+ playerDisplay.pSelect->SetVisible( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the spectator list
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdateSpectatorList()
+{
+ if ( g_PR == NULL )
+ {
+ return;
+ }
+
+ const int listTextLen = 100;
+ wchar_t listText[listTextLen];
+ listText[0] = L'\0';
+
+ const wchar_t *delimText = L", ";
+ const int delimTextLen = V_wcslen( delimText );
+
+ // Count the number of spectators and build up a list.
+ int nSpectators = 0;
+ for ( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; ++playerIndex )
+ {
+ if ( ShouldShowAsSpectator( playerIndex ) )
+ {
+ const char *playerName = g_PR->GetPlayerName( playerIndex );
+ if ( playerName != NULL )
+ {
+ // Convert the name to wide char.
+ wchar_t playerBuf[MAX_PLAYER_NAME_LENGTH];
+ playerBuf[0] = L'\0';
+ V_UTF8ToUnicode( playerName, playerBuf, sizeof( playerBuf ) );
+
+ //
+ // Check to see if there is space for the player name and delimiter.
+ //
+
+ bool addDelim = ( nSpectators > 0 );
+
+ int playerNameLen = V_wcslen( playerBuf );
+ if ( addDelim )
+ {
+ playerNameLen += delimTextLen;
+ }
+
+ int currentLen = V_wcslen( listText );
+ int remainingLen = listTextLen - currentLen - playerNameLen - 1;
+ if ( remainingLen >= 0 )
+ {
+ // Append the delimiter.
+ if ( addDelim )
+ {
+ V_wcscat_safe( listText, delimText );
+ }
+
+ // Append the player name.
+ V_wcscat_safe( listText, playerBuf );
+ }
+ }
+
+ ++nSpectators;
+ }
+ }
+
+ wchar_t labelText[512];
+ labelText[0] = L'\0';
+
+ if ( nSpectators == 0 )
+ {
+ // No spectators.
+ wchar_t *noSpectators = g_pVGuiLocalize->Find( "#Cstrike_Scoreboard_NoSpectators" );
+ if ( noSpectators != NULL )
+ {
+ V_wcsncpy( labelText, noSpectators, sizeof( labelText ) );
+ }
+ }
+ else
+ {
+ // Build the text for the number of spectators.
+ const int countTextLen = 16;
+ wchar_t countText[countTextLen];
+ countText[0] = L'\0';
+ V_snwprintf( countText, countTextLen, L"%i", nSpectators );
+ countText[countTextLen - 1] = L'\0';
+
+ // Build the combined count and spectator list text.
+ wchar_t *formatLabel = g_pVGuiLocalize->Find( ( nSpectators == 1 ) ? "#Cstrike_Scoreboard_Spectator" : "#Cstrike_Scoreboard_Spectators" );
+ if ( formatLabel != NULL )
+ {
+ g_pVGuiLocalize->ConstructString( labelText, sizeof( labelText ), formatLabel, 2, countText, listText );
+ }
+ }
+
+ SetDialogVariable( "spectators", labelText );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Display the number of HLTV viewers
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdateHLTVList( void )
+{
+ // Build the text for the number of viewers.
+ const int countTextLen = 16;
+ wchar_t countText[countTextLen];
+ countText[0] = L'\0';
+ V_snwprintf( countText, countTextLen, L"%i", m_HLTVSpectators );
+ countText[countTextLen - 1] = L'\0';
+
+ // Build the combined text.
+ wchar_t labelText[512];
+ labelText[0] = L'\0';
+ wchar_t *formatLabel = g_pVGuiLocalize->Find( "#Cstrike_Scoreboard_HLTV" );
+ if ( formatLabel != NULL )
+ {
+ g_pVGuiLocalize->ConstructString( labelText, sizeof( labelText ), formatLabel, 1, countText );
+ }
+
+ SetDialogVariable( "sourcetv", labelText );
+}
+
+/**
+* Special processing for MVP UI elements
+*/
+void CCSClientScoreBoardDialog::UpdateMvpElements()
+{
+ C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR );
+ if ( cs_PR == NULL )
+ {
+ return;
+ }
+
+ for ( int teamIndex = TEAM_TERRORIST; teamIndex <= TEAM_CT; ++teamIndex )
+ {
+ TeamDisplayInfo& teamDisplay = ( teamIndex == TEAM_TERRORIST ) ? m_teamDisplayT : m_teamDisplayCT;
+
+ for ( int i = 0; i < cMaxScoreLines && i < teamDisplay.playerScores.Count(); ++i )
+ {
+ PlayerDisplay& playerDisplay = teamDisplay.playerDisplay[i];
+
+ // Get the player index.
+ int playerIndex = -1;
+ if ( teamDisplay.playerScores[i] != NULL )
+ {
+ playerIndex = teamDisplay.playerScores[i]->playerIndex;
+ }
+
+ if ( playerIndex == -1 )
+ continue;
+
+ // early out fail conditions
+ if ( playerDisplay.pNameLabel == NULL || playerDisplay.pMVPImage == NULL || playerDisplay.pMVPCountLabel == NULL )
+ continue;
+
+ // Get the number of MVPs and cap it.
+ int numMVPs = MIN( kMaxMVPCount, cs_PR->GetNumMVPs( playerIndex ) );
+
+ // No MVPs.
+ if ( numMVPs == 0 )
+ {
+ playerDisplay.pMVPImage->SetVisible( false );
+ playerDisplay.pMVPCountLabel->SetVisible( false );
+ continue;
+ }
+
+ // Get the dimensions of the player label.
+ int xName = 0;
+ int yName = 0;
+ int wideName = 0;
+ int tallName = 0;
+ playerDisplay.pNameLabel->GetBounds( xName, yName, wideName, tallName );
+
+ wchar_t playerName[64];
+ playerDisplay.pNameLabel->GetText( playerName, sizeof(playerName) );
+
+ // Find the actual width of the rendered player name.
+ int actualWideName = 0;
+ int actualTallName = 0;
+ g_pMatSystemSurface->GetTextSize( playerDisplay.pNameLabel->GetFont(), playerName, actualWideName, actualTallName );
+ if ( actualWideName > wideName )
+ {
+ actualWideName = wideName;
+ }
+
+ // Get the dimensions of the mvp image.
+ int xMVPImage = 0;
+ int yMVPImage = 0;
+ int wideMVPImage = 0;
+ int tallMVPImage = 0;
+ playerDisplay.pMVPImage->GetBounds( xMVPImage, yMVPImage, wideMVPImage, tallMVPImage );
+
+ // The MVP label is hidden for only one star.
+ bool showMVPNumber = ( numMVPs > 1 );
+
+ // Set the MVP label text and get the actual size.
+ int actualWideMVPLabel = 0;
+ if ( showMVPNumber )
+ {
+ const int mvpTextSize = 8;
+ wchar_t mvpText[mvpTextSize];
+ V_snwprintf( mvpText, ARRAYSIZE( mvpText ), L"%i", numMVPs );
+ playerDisplay.pMVPCountLabel->SetText( mvpText );
+ playerDisplay.pMVPCountLabel->SetVisible( true );
+
+ int actualTallMVPLabel = 0;
+ g_pMatSystemSurface->GetTextSize( playerDisplay.pMVPCountLabel->GetFont(), mvpText, actualWideMVPLabel, actualTallMVPLabel );
+ }
+
+ // Calculate the total width of the mvp stuff.
+ int wideMVPTotal = wideMVPImage;
+ if ( showMVPNumber )
+ {
+ wideMVPTotal += actualWideMVPLabel;
+ }
+
+ // Calculate the optimal place for the mvp.
+ int x = xName + actualWideName + m_MVPXOffset;
+
+ // Get the position of the status image.
+ if ( playerDisplay.pStatusImage )
+ {
+ int xStatus = 0;
+ int yStatus = 0;
+ playerDisplay.pStatusImage->GetPos( xStatus, yStatus );
+
+ if ( x + wideMVPTotal > xStatus )
+ {
+ // Don't run over the status image. Back up.
+ x = xStatus - wideMVPTotal;
+ }
+ }
+
+ playerDisplay.pMVPImage->SetPos( x, yMVPImage );
+ playerDisplay.pMVPImage->SetVisible( true );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether the specified player index is a spectator
+//-----------------------------------------------------------------------------
+bool CCSClientScoreBoardDialog::ShouldShowAsSpectator( int iPlayerIndex )
+{
+ C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR );
+ if ( !cs_PR )
+ return false;
+
+ // see if player is connected
+ if ( cs_PR->IsConnected( iPlayerIndex ) )
+ {
+ // either spectator or unassigned team should show in spectator list
+ int iTeam = cs_PR->GetTeam( iPlayerIndex );
+ if ( TEAM_SPECTATOR == iTeam || TEAM_UNASSIGNED == iTeam )
+ return true;
+ }
+ return false;
+}
+
+
+void CCSClientScoreBoardDialog::FireGameEvent( IGameEvent *event )
+{
+ if ( event == NULL )
+ return;
+
+ const char *pEventName = event->GetName();
+ if ( pEventName == NULL )
+ return;
+
+ if ( Q_strcmp( pEventName, "server_spawn" ) == 0 )
+ {
+ // set server name in scoreboard
+ const char *hostname = event->GetString( "hostname" );
+ if ( hostname != NULL )
+ {
+ wchar_t wzHostName[256];
+ g_pVGuiLocalize->ConvertANSIToUnicode( hostname, wzHostName, sizeof( wzHostName ) );
+ g_pVGuiLocalize->ConstructString( m_pServerName, sizeof(m_pServerName), g_pVGuiLocalize->Find( "#Cstrike_SB_Server" ), 1, wzHostName );
+
+ if ( m_pServerLabel )
+ {
+ m_pServerLabel->SetText( m_pServerName );
+ }
+
+ if ( m_gameOver )
+ {
+ ResetFromGameOverState();
+ }
+
+ // Save the server name for use after this panel is reconstructed
+ if ( g_pClientMode )
+ {
+ g_pClientMode->SetServerName( m_pServerName );
+ }
+ }
+ }
+ else if ( Q_strcmp( pEventName, "game_newmap" ) == 0 )
+ {
+ const char *mapName = event->GetString( "mapname" );
+ if ( mapName != NULL )
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode( mapName, m_pMapName, sizeof( m_pMapName ) );
+ SetDialogVariable( "mapname", m_pMapName );
+
+ if ( m_gameOver )
+ {
+ ResetFromGameOverState();
+ }
+
+ // Save the map name for use after this panel is reconstructed
+ if ( g_pClientMode )
+ {
+ g_pClientMode->SetMapName( m_pMapName );
+ }
+ }
+ }
+ else if ( Q_strcmp( pEventName, "match_end_conditions" ) == 0 )
+ {
+ UpdateMatchEndText();
+ }
+ else if ( Q_strcmp( pEventName, "cs_win_panel_match" ) == 0 )
+ {
+ m_gameOver = true;
+ UpdateMatchEndText();
+ }
+
+ BaseClass::FireGameEvent( event );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a new row to the scoreboard, from the playerinfo structure
+//-----------------------------------------------------------------------------
+bool CCSClientScoreBoardDialog::GetPlayerScoreInfo( int playerIndex, PlayerScoreInfo& playerScoreInfo )
+{
+ if ( g_PR == NULL )
+ return false;
+
+ // Clean up the player name
+ const char *oldName = g_PR->GetPlayerName( playerIndex );
+ if ( oldName == NULL )
+ return false;
+
+ playerScoreInfo.szName = g_PR->GetPlayerName( playerIndex );
+
+ playerScoreInfo.playerIndex = playerIndex;
+ playerScoreInfo.frags = g_PR->GetPlayerScore( playerIndex );
+ playerScoreInfo.deaths = g_PR->GetDeaths( playerIndex );
+
+ if ( g_PR->GetPing( playerIndex ) < 1 )
+ {
+ if ( g_PR->IsFakePlayer( playerIndex ) )
+ {
+ playerScoreInfo.ping = -1;
+ }
+ else
+ {
+ playerScoreInfo.ping = 0;
+ }
+ }
+ else
+ {
+ playerScoreInfo.ping = g_PR->GetPing( playerIndex );
+ }
+
+ // get CS specific infos
+ C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR );
+
+ C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( !cs_PR || !pLocalPlayer )
+ {
+ return false;
+ }
+
+ // Get the clan tag
+ playerScoreInfo.szClanTag = cs_PR->GetClanTag( playerIndex );
+
+ bool bShowExtraInfo =
+ ( pLocalPlayer->GetTeamNumber() == TEAM_UNASSIGNED ) || // we're not spawned yet
+ ( pLocalPlayer->GetTeamNumber() == TEAM_SPECTATOR ) || // we are a spectator
+ ( pLocalPlayer->IsPlayerDead() && mp_forcecamera.GetInt() == OBS_ALLOW_ALL ) || // we are dead and allowed to spectate opponents
+ ( pLocalPlayer->GetTeamNumber() == g_PR->GetTeam( playerIndex ) ); // we're on the same team
+
+ playerScoreInfo.szStatus = NULL;
+ playerScoreInfo.bStatusPlayerColor = false;
+
+ // set the status icon; lowest priority icons are tested first, and highest last
+
+ if ( cs_PR->IsVIP( playerIndex ) && bShowExtraInfo )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_clock";
+ playerScoreInfo.bStatusPlayerColor = true;
+ }
+
+ if ( !g_PR->IsAlive( playerIndex ) && g_PR->GetTeam( playerIndex ) > TEAM_SPECTATOR )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_dead";
+ }
+
+ if ( g_PR->IsHLTV( playerIndex ) )
+ {
+// // show #spectators in class field, it's transmitted as player's score
+// char numspecs[32];
+// Q_snprintf( numspecs, sizeof( numspecs ), "%i Spectators", m_HLTVSpectators );
+// kv->SetString( "class", numspecs );
+ }
+
+ // Set the dominated icon
+ if ( pLocalPlayer->IsPlayerDominatingMe( playerIndex ) )
+ {
+ if ( g_PR->IsAlive( playerIndex ) )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_nemesis";
+ }
+ else
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_nemesis-dead";
+ }
+ }
+
+ if ( pLocalPlayer->IsPlayerDominated(playerIndex) )
+ {
+ if ( g_PR->IsAlive( playerIndex ) )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_dominated";
+ }
+ else
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_domination-dead";
+ }
+ }
+
+ if ( cs_PR->HasC4( playerIndex ) && bShowExtraInfo )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_bomb";
+ playerScoreInfo.bStatusPlayerColor = true;
+ }
+
+ if ( cs_PR->HasDefuser( playerIndex ) && bShowExtraInfo )
+ {
+ playerScoreInfo.szStatus = "../hud/scoreboard_defuser";
+ playerScoreInfo.bStatusPlayerColor = true;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the time/round remaining display and server and map name
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdateMatchEndText()
+{
+ // Hide the win condition.
+ if ( m_pWinConditionLabel )
+ {
+ m_pWinConditionLabel->SetVisible( false );
+ }
+
+ // Hide the clock.
+ if ( m_pClockLabel )
+ {
+ m_pClockLabel->SetVisible( false );
+ }
+
+ if ( !m_gameOver )
+ {
+ SetDialogVariable( "mapname", m_pMapName );
+
+ wchar_t wzMatchEndCausesLabel[128], wzMatchEndCause[32];
+
+ // Time limit
+ if ( mp_timelimit.GetInt() != 0 )
+ {
+ int timeTillEndOfMatch = CSGameRules()->GetMapRemainingTime();
+ bool showTime = ( timeTillEndOfMatch != -1 );
+ if ( showTime )
+ {
+ if ( m_pWinConditionLabel )
+ {
+ V_snwprintf( wzMatchEndCause, ARRAYSIZE( wzMatchEndCause ), L"%.2i:%.2i", timeTillEndOfMatch / 60, timeTillEndOfMatch % 60 );
+ g_pVGuiLocalize->ConstructString( wzMatchEndCausesLabel, sizeof( wzMatchEndCausesLabel ),
+ g_pVGuiLocalize->Find( "#Cstrike_Time_LeftVariable" ), 1, wzMatchEndCause );
+ m_pWinConditionLabel->SetText( wzMatchEndCausesLabel );
+ m_pWinConditionLabel->SetVisible( true );
+ }
+
+ if ( m_pClockLabel )
+ {
+ m_pClockLabel->SetVisible( true );
+ }
+ }
+ }
+ // Round limit
+ else if ( mp_maxrounds.GetInt() != 0 )
+ {
+ if ( m_pWinConditionLabel )
+ {
+ // Get the number of rounds played.
+ int roundsPlayed = 0;
+ for ( int teamIndex = TEAM_TERRORIST; teamIndex <= TEAM_CT; teamIndex++ )
+ {
+ C_Team *team = GetGlobalTeam( teamIndex );
+ if ( team )
+ {
+ roundsPlayed += team->Get_Score();
+ }
+ }
+
+ V_snwprintf( wzMatchEndCause, ARRAYSIZE( wzMatchEndCause ), L"%d", mp_maxrounds.GetInt() - roundsPlayed );
+ g_pVGuiLocalize->ConstructString( wzMatchEndCausesLabel, sizeof( wzMatchEndCausesLabel ),
+ g_pVGuiLocalize->Find( "#Cstrike_Rounds_LeftVariable" ), 1, wzMatchEndCause );
+ m_pWinConditionLabel->SetText( wzMatchEndCausesLabel );
+ m_pWinConditionLabel->SetVisible( true );
+ }
+ }
+ // Win limit
+ else if ( mp_winlimit.GetInt() != 0 )
+ {
+ if ( m_pWinConditionLabel )
+ {
+ V_snwprintf( wzMatchEndCause, ARRAYSIZE( wzMatchEndCause ), L"%d", mp_winlimit.GetInt() );
+ g_pVGuiLocalize->ConstructString( wzMatchEndCausesLabel, sizeof( wzMatchEndCausesLabel ),
+ g_pVGuiLocalize->Find( "#Cstrike_Wins_NeededVariable" ), 1, wzMatchEndCause );
+ m_pWinConditionLabel->SetText( wzMatchEndCausesLabel );
+ m_pWinConditionLabel->SetVisible( true );
+ }
+ }
+ }
+}
+
+// Resets all changes made by the scoreboard's state at the match end
+void CCSClientScoreBoardDialog::ResetFromGameOverState()
+{
+ m_gameOver = false;
+
+ if ( m_pLabelMapName )
+ {
+ m_pLabelMapName->SetVisible( true );
+ }
+
+ UpdateMatchEndText();
+}
+
+// [tj] We hook into the show command so we can lock or unlock all the elements that need to be hidden
+//
+// [pfreese] This used to enable/disable keyboard input, but since the scoreboard is now a popup, we have
+// to leave the keyboard disabled
+void CCSClientScoreBoardDialog::ShowPanel( bool state )
+{
+ BaseClass::ShowPanel(state);
+
+ int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_scoreboard" );
+
+ if ( state )
+ {
+ gHUD.LockRenderGroup( iRenderGroup );
+ }
+ else
+ {
+ gHUD.UnlockRenderGroup( iRenderGroup );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Grabs the player data colors from the convars.
+//-----------------------------------------------------------------------------
+void CCSClientScoreBoardDialog::UpdatePlayerColors( void )
+{
+ m_teamDisplayT.playerDataColor.SetColor( cl_scoreboard_t_color_red.GetInt(), cl_scoreboard_t_color_green.GetInt(), cl_scoreboard_t_color_blue.GetInt(), 255 );
+ m_teamDisplayCT.playerDataColor.SetColor( cl_scoreboard_ct_color_red.GetInt(), cl_scoreboard_ct_color_green.GetInt(), cl_scoreboard_ct_color_blue.GetInt(), 255 );
+ m_DeadPlayerDataColor.SetColor( cl_scoreboard_dead_color_red.GetInt(), cl_scoreboard_dead_color_green.GetInt(), cl_scoreboard_dead_color_blue.GetInt(), 255 );
+ m_teamDisplayT.playerClanColor.SetColor( cl_scoreboard_clan_t_color_red.GetInt(), cl_scoreboard_clan_t_color_green.GetInt(), cl_scoreboard_clan_t_color_blue.GetInt(), 255 );
+ m_teamDisplayCT.playerClanColor.SetColor( cl_scoreboard_clan_ct_color_red.GetInt(), cl_scoreboard_clan_ct_color_green.GetInt(), cl_scoreboard_clan_ct_color_blue.GetInt(), 255 );
+ m_DeadPlayerClanColor.SetColor( cl_scoreboard_dead_clan_color_red.GetInt(), cl_scoreboard_dead_clan_color_green.GetInt(), cl_scoreboard_dead_clan_color_blue.GetInt(), 255 );
+}
+
+// [tj] Disabling joystick input if you are dead.
+void CCSClientScoreBoardDialog::OnThink()
+{
+ BaseClass::OnThink();
+
+#ifdef _XBOX
+ C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( pLocalPlayer )
+ {
+ bool mouseEnabled = IsMouseInputEnabled();
+ if (pLocalPlayer->IsAlive() == mouseEnabled)
+ {
+ SetMouseInputEnabled( !mouseEnabled );
+ }
+ }
+#endif
+}
+
+bool CCSClientScoreBoardDialog::ForceLocalPlayerVisible( TeamDisplayInfo& teamDisplay )
+{
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+
+ // Look for the local player in the non-visible portion of the member list
+ for (int i = teamDisplay.maxPlayersVisible; i < teamDisplay.playerScores.Count(); ++i)
+ {
+ PlayerScoreInfo* pPlayerScore = teamDisplay.playerScores[i];
+ Assert(pPlayerScore != NULL);
+
+ // Determine if this is the local player's entry
+ if ( pPlayerScore->playerIndex == iLocalPlayerIndex )
+ {
+ // Remove the local player entry from the current position
+ teamDisplay.playerScores.Remove(i);
+
+ // Re-insert the local player entry at the end of the visible list
+ teamDisplay.playerScores.InsertBefore( teamDisplay.maxPlayersVisible - 1, pPlayerScore );
+
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/game/client/cstrike/VGUI/cstrikeclientscoreboard.h b/game/client/cstrike/VGUI/cstrikeclientscoreboard.h
new file mode 100644
index 0000000..2a2e409
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikeclientscoreboard.h
@@ -0,0 +1,153 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSTRIKECLIENTSCOREBOARDDIALOG_H
+#define CSTRIKECLIENTSCOREBOARDDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <clientscoreboarddialog.h>
+#include <vgui_controls/ImagePanel.h>
+#include "cs_shareddefs.h"
+#include <vgui_controls/Frame.h>
+#include "vgui_avatarimage.h"
+
+
+const int cMaxScoreLines = 32; // This value must be > 2
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Game ScoreBoard
+//-----------------------------------------------------------------------------
+class CCSClientScoreBoardDialog : public CClientScoreBoardDialog
+{
+private:
+ DECLARE_CLASS_SIMPLE( CCSClientScoreBoardDialog, CClientScoreBoardDialog );
+
+public:
+ CCSClientScoreBoardDialog( IViewPort *pViewPort );
+ ~CCSClientScoreBoardDialog();
+
+ virtual void Update();
+
+ // vgui overrides for rounded corner background
+ void UpdateMvpElements();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual void ResetFromGameOverState();
+
+ // [tj] Hook in here to hide other UI
+ virtual void ShowPanel( bool state );
+
+ // [tj] So we can do processing every frame
+ virtual void OnThink();
+
+protected:
+
+ struct PlayerScoreInfo
+ {
+ const char* szName;
+ const char* szClanTag;
+ int playerIndex;
+ int frags;
+ int deaths;
+ int ping;
+ const char* szStatus;
+ bool bStatusPlayerColor;
+ };
+
+ struct PlayerDisplay
+ {
+ vgui::Label* pNameLabel;
+ vgui::Label* pClanLabel;
+ vgui::Label* pScoreLabel;
+ vgui::Label* pDeathsLabel;
+ vgui::Label* pPingLabel;
+ vgui::Label* pMVPCountLabel;
+ CAvatarImagePanel* pAvatar;
+ vgui::ImagePanel* pStatusImage;
+ vgui::ImagePanel* pMVPImage;
+ vgui::ImagePanel* pSelect;
+ };
+
+ struct TeamDisplayInfo
+ {
+ Color playerDataColor;
+ Color playerClanColor;
+ PlayerDisplay playerDisplay[cMaxScoreLines];
+ CUtlVector<PlayerScoreInfo*> playerScores; // For sorting team members outside of the listboxes
+ int scoreAreaInnerHeight;
+ int scoreAreaLineHeight;
+ int scoreAreaLinePreferredLeading;
+ int scoreAreaStartY;
+ int scoreAreaMinX;
+ int scoreAreaMaxX;
+ int maxPlayersVisible;
+ };
+
+ bool GetPlayerScoreInfo( int playerIndex, PlayerScoreInfo& playerScoreInfo );
+ void UpdateTeamPlayerDisplay( TeamDisplayInfo& teamDisplay );
+ void SetupTeamDisplay( TeamDisplayInfo& teamDisplay, const char* szTeamPrefix );
+
+ void UpdateTeamInfo();
+ void UpdatePlayerList();
+
+ bool ForceLocalPlayerVisible( TeamDisplayInfo& teamDisplay );
+ void UpdateSpectatorList();
+ void UpdateHLTVList( void );
+ void UpdateMatchEndText();
+
+ bool ShouldShowAsSpectator( int iPlayerIndex );
+ void FireGameEvent( IGameEvent *event );
+
+ void UpdatePlayerColors( void );
+ void AdjustFontToFit( const char *pString, vgui::Label *pLabel );
+
+ static int PlayerSortFunction( PlayerScoreInfo* const* pPS1, PlayerScoreInfo* const* pPS2 );
+
+private:
+ vgui::HFont m_listItemFont;
+ vgui::HFont m_listItemFontSmaller;
+ vgui::HFont m_listItemFontSmallest;
+ vgui::HFont m_MVPFont;
+
+ int m_iImageDead;
+ int m_iImageMVP; // Not used in the section list explicitly. Drawn over it
+ int m_iImageDominated;
+ int m_iImageNemesis;
+ int m_iImageBomb;
+ int m_iImageVIP;
+ int m_iImageFriend;
+ int m_iImageNemesisDead;
+ int m_iImageDominationDead;
+
+ Color m_DeadPlayerDataColor;
+ Color m_PlayerDataBgColor;
+ Color m_DeadPlayerClanColor;
+
+ vgui::Label* m_pWinConditionLabel;
+ vgui::Label* m_pClockLabel;
+ vgui::Label* m_pLabelMapName;
+ vgui::Label* m_pServerLabel;
+
+ bool m_gameOver;
+
+ wchar_t m_pMapName[256];
+ wchar_t m_pServerName[256];
+ wchar_t m_pStatsEnabled[256];
+ wchar_t m_pStatsDisabled[256];
+
+ int m_LocalPlayerItemID;
+ int m_MVPXOffset;
+
+ TeamDisplayInfo m_teamDisplayT;
+ TeamDisplayInfo m_teamDisplayCT;
+};
+
+
+#endif // CSTRIKECLIENTSCOREBOARDDIALOG_H
diff --git a/game/client/cstrike/VGUI/cstrikespectatorgui.cpp b/game/client/cstrike/VGUI/cstrikespectatorgui.cpp
new file mode 100644
index 0000000..9c633c1
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikespectatorgui.cpp
@@ -0,0 +1,2324 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstrikespectatorgui.h"
+#include "hud.h"
+#include "cs_shareddefs.h"
+
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <filesystem.h>
+#include "cs_gamerules.h"
+#include "c_team.h"
+#include "c_cs_playerresource.h"
+#include "c_plantedc4.h"
+#include "c_cs_hostage.h"
+#include "vtf/vtf.h"
+#include "clientmode.h"
+#include <vgui_controls/AnimationController.h>
+#include "voice_status.h"
+#include "hud_radar.h"
+
+using namespace vgui;
+DECLARE_HUDELEMENT( CCSMapOverview )
+
+extern ConVar overview_health;
+extern ConVar overview_names;
+extern ConVar overview_tracks;
+extern ConVar overview_locked;
+extern ConVar overview_alpha;
+extern ConVar cl_radaralpha;
+ConVar cl_radar_locked( "cl_radar_locked", "0", FCVAR_ARCHIVE, "Lock the angle of the radar display?" );
+
+void PreferredOverviewModeChanged( IConVar *pConVar, const char *oldString, float flOldValue )
+{
+ ConVarRef var( pConVar );
+ char cmd[32];
+ V_snprintf( cmd, sizeof( cmd ), "overview_mode %d\n", var.GetInt() );
+ engine->ClientCmd( cmd );
+}
+ConVar overview_preferred_mode( "overview_preferred_mode", "1", FCVAR_ARCHIVE, "Preferred overview mode", PreferredOverviewModeChanged );
+
+ConVar overview_preferred_view_size( "overview_preferred_view_size", "600", FCVAR_ARCHIVE, "Preferred overview view size" );
+
+#define HOSTAGE_RESCUE_DURATION (2.5f)
+#define BOMB_FADE_DURATION (2.5f)
+#define DEATH_ICON_FADE (7.5f)
+#define DEATH_ICON_DURATION (10.0f)
+#define LAST_SEEN_ICON_DURATION (4.0f)
+#define DIFFERENCE_THRESHOLD (200.0f)
+
+// To make your own green radar file from the map overview file, turn this on, and include vtf.lib
+#define no_GENERATE_RADAR_FILE
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSSpectatorGUI::CCSSpectatorGUI(IViewPort *pViewPort) : CSpectatorGUI(pViewPort)
+{
+ m_pCTLabel = NULL;
+ m_pCTScore = NULL;
+ m_pTerLabel = NULL;
+ m_pTerScore = NULL;
+ m_pTimer = NULL;
+ m_pTimerLabel = NULL;
+ m_pDivider = NULL;
+ m_pExtraInfo = NULL;
+
+ m_modifiedWidths = false;
+
+ m_scoreWidth = 0;
+ m_extraInfoWidth = 0;
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // Grab some control pointers
+ m_pCTLabel = dynamic_cast<Label *>(FindChildByName("CTScoreLabel"));
+ m_pCTScore = dynamic_cast<Label *>(FindChildByName("CTScoreValue"));
+ m_pTerLabel = dynamic_cast<Label *>(FindChildByName("TerScoreLabel"));
+ m_pTerScore = dynamic_cast<Label *>(FindChildByName("TerScoreValue"));
+
+ m_pTimer = dynamic_cast<Label *>(FindChildByName("timerclock"));
+ m_pTimerLabel = dynamic_cast<Label *>(FindChildByName("timerlabel"));
+
+ m_pDivider = dynamic_cast<Panel *>(FindChildByName("DividerBar"));
+
+ m_pExtraInfo = dynamic_cast<Label *>(FindChildByName("extrainfo"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resets the list of players
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::UpdateSpectatorPlayerList()
+{
+ C_Team *cts = GetGlobalTeam( TEAM_CT );
+ if ( cts )
+ {
+ wchar_t frags[ 10 ];
+ _snwprintf( frags, ARRAYSIZE( frags ), L"%i", cts->Get_Score() );
+
+ SetLabelText( "CTScoreValue", frags );
+ }
+
+ C_Team *ts = GetGlobalTeam( TEAM_TERRORIST );
+ if ( ts )
+ {
+ wchar_t frags[ 10 ];
+ _snwprintf( frags, ARRAYSIZE( frags ), L"%i", ts->Get_Score() );
+
+ SetLabelText( "TERScoreValue", frags );
+ }
+}
+
+bool CCSSpectatorGUI::NeedsUpdate( void )
+{
+ C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
+ if ( !player )
+ return false;
+
+ if ( m_nLastAccount != player->GetAccount() )
+ return true;
+
+ if ( m_nLastTime != (int)CSGameRules()->GetRoundRemainingTime() )
+ return true;
+
+ if ( m_nLastSpecMode != player->GetObserverMode() )
+ return true;
+
+ if ( m_nLastSpecTarget != player->GetObserverTarget() )
+ return true;
+
+ return BaseClass::NeedsUpdate();
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [smessick]
+//=============================================================================
+void CCSSpectatorGUI::ShowPanel( bool bShow )
+{
+ BaseClass::ShowPanel( bShow );
+
+ if ( bShow )
+ {
+ // Resend the overview command.
+ char cmd[32];
+ V_snprintf( cmd, sizeof( cmd ), "overview_mode %d\n", overview_preferred_mode.GetInt() );
+ engine->ClientCmd( cmd );
+ }
+}
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the timer label if one exists
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::UpdateTimer()
+{
+ // these could be NULL if players modified the UI
+ if ( !ControlsPresent() )
+ return;
+
+ Color timerColor = m_pTimer->GetFgColor();
+ if( g_PlantedC4s.Count() > 0 )
+ {
+ m_pTimer->SetText( "\\" ); // bomb icon
+ m_pTimerLabel->SetVisible( false );
+
+ if( g_PlantedC4s[0]->m_flNextGlow > gpGlobals->curtime + 0.1f )
+ timerColor[3] = 80;
+ else
+ timerColor[3] = 255;
+
+ m_pTimer->SetFgColor( timerColor );
+ return;
+ }
+
+ timerColor[3] = 255;
+ m_pTimer->SetFgColor( timerColor );
+ m_pTimer->SetText( "e" ); // clock icon
+
+ m_nLastTime = (int)( CSGameRules()->GetRoundRemainingTime() );
+
+ if ( m_nLastTime < 0 )
+ m_nLastTime = 0;
+
+ wchar_t szText[ 63 ];
+ _snwprintf ( szText, ARRAYSIZE( szText ), L"%d:%02d", (m_nLastTime / 60), (m_nLastTime % 60) );
+ szText[62] = 0;
+
+ SetLabelText("timerlabel", szText );
+ m_pTimerLabel->SetVisible( true );
+}
+
+void CCSSpectatorGUI::UpdateAccount()
+{
+ C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( !player )
+ return;
+
+ m_nLastAccount = player->GetAccount();
+
+ if ( (player->GetTeamNumber() == TEAM_TERRORIST) || (player->GetTeamNumber() == TEAM_CT) )
+ {
+ wchar_t szText[ 63 ];
+ _snwprintf ( szText, ARRAYSIZE( szText ), L"$%i", m_nLastAccount );
+ szText[62] = 0;
+
+ SetLabelText( "extrainfo", szText );
+ }
+}
+
+
+/*bool CCSSpectatorGUI::CanSpectateTeam( int iTeam )
+{
+ bool bRetVal = true;
+ int iTeamOnly = 0;// TODO = gCSViewPortInterface->GetForceCamera();
+
+ // if we're not a spectator or HLTV and iTeamOnly is set
+ if ( C_BasePlayer::GetLocalPlayer()->GetTeamNumber() // && !gEngfuncs.IsSpectateOnly()
+ && iTeamOnly )
+ {
+ // then we want to force the same team
+ if ( C_BasePlayer::GetLocalPlayer()->GetTeamNumber() != iTeam )
+ {
+ bRetVal = false;
+ }
+ }
+
+ return bRetVal;
+}*/
+
+void CCSSpectatorGUI::Update()
+{
+ BaseClass::Update();
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if( pLocalPlayer )
+ {
+ m_nLastSpecMode = pLocalPlayer->GetObserverMode();
+ m_nLastSpecTarget = pLocalPlayer->GetObserverTarget();
+ }
+
+ UpdateTimer();
+
+ UpdateAccount();
+
+ UpdateSpectatorPlayerList();
+
+ if ( pLocalPlayer )
+ {
+ ResizeControls();
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Save off widths for sizing calculations
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::StoreWidths( void )
+{
+ if ( !ControlsPresent() )
+ return;
+
+ if ( !m_modifiedWidths )
+ {
+ m_scoreWidth = m_pCTScore->GetWide();
+ int terScoreWidth = m_pTerScore->GetWide();
+
+ m_extraInfoWidth = m_pExtraInfo->GetWide();
+
+ if ( m_scoreWidth != terScoreWidth )
+ {
+ m_pTerScore = NULL; // We're working with a modified res file. Don't muck things up playing with positioning.
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resize controls so scores & map names are not cut off
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::ResizeControls( void )
+{
+ if ( !ControlsPresent() )
+ return;
+
+ int x1, y1, w1, t1;
+ int x2, y2, w2, t2;
+
+ StoreWidths();
+
+ // ensure scores are wide enough
+ int wCT, hCT, wTer, hTer;
+ m_pCTScore->GetBounds( x1, y1, w1, t1 );
+ m_pCTScore->GetContentSize( wCT, hCT );
+ m_pTerScore->GetBounds( x2, y2, w2, t2 );
+ m_pTerScore->GetContentSize( wTer, hTer );
+
+ int desiredScoreWidth = m_scoreWidth;
+ desiredScoreWidth = MAX( desiredScoreWidth, wCT );
+ desiredScoreWidth = MAX( desiredScoreWidth, wTer );
+
+ int diff = desiredScoreWidth - w1;
+ if ( diff != 0 )
+ {
+ m_pCTScore->GetBounds( x1, y1, w1, t1 );
+ m_pCTScore->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pTerScore->GetBounds( x1, y1, w1, t1 );
+ m_pTerScore->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pCTLabel->GetPos( x1, y1 );
+ m_pCTLabel->SetPos( x1 - diff, y1 );
+
+ m_pTerLabel->GetPos( x1, y1 );
+ m_pTerLabel->SetPos( x1 - diff, y1 );
+
+ m_modifiedWidths = true;
+ }
+
+ // ensure extra info is wide enough
+ int wExtra, hExtra;
+ m_pExtraInfo->GetBounds( x1, y1, w1, t1 );
+ m_pExtraInfo->GetContentSize( wExtra, hExtra );
+
+ int desiredExtraWidth = m_extraInfoWidth;
+ desiredExtraWidth = MAX( desiredExtraWidth, wExtra );
+
+ diff = desiredExtraWidth - w1;
+ if ( diff != 0 )
+ {
+ m_pExtraInfo->GetBounds( x1, y1, w1, t1 );
+ m_pExtraInfo->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pTimer->GetPos( x1, y1 );
+ m_pTimer->SetPos( x1 - diff, y1 );
+
+ m_pTimerLabel->GetPos( x1, y1 );
+ m_pTimerLabel->SetPos( x1 - diff, y1 );
+
+ m_pDivider->GetPos( x1, y1 );
+ m_pDivider->SetPos( x1 - diff, y1 );
+
+ m_pCTScore->GetPos( x1, y1 );
+ m_pCTScore->SetPos( x1 - diff, y1 );
+
+ m_pCTLabel->GetPos( x1, y1 );
+ m_pCTLabel->SetPos( x1 - diff, y1 );
+
+ m_pTerScore->GetPos( x1, y1 );
+ m_pTerScore->SetPos( x1 - diff, y1 );
+
+ m_pTerLabel->GetPos( x1, y1 );
+ m_pTerLabel->SetPos( x1 - diff, y1 );
+
+ m_modifiedWidths = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Verify controls are present to resize
+//-----------------------------------------------------------------------------
+bool CCSSpectatorGUI::ControlsPresent( void ) const
+{
+ return ( m_pCTLabel != NULL &&
+ m_pCTScore != NULL &&
+ m_pTerLabel != NULL &&
+ m_pTerScore != NULL &&
+ m_pTimer != NULL &&
+ m_pTimerLabel != NULL &&
+ m_pDivider != NULL &&
+ m_pExtraInfo != NULL );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+static int AdjustValue( int curValue, int targetValue, int amount )
+{
+ if ( curValue > targetValue )
+ {
+ curValue -= amount;
+
+ if ( curValue < targetValue )
+ curValue = targetValue;
+ }
+ else if ( curValue < targetValue )
+ {
+ curValue += amount;
+
+ if ( curValue > targetValue )
+ curValue = targetValue;
+ }
+
+ return curValue;
+}
+
+void CCSMapOverview::InitTeamColorsAndIcons()
+{
+ BaseClass::InitTeamColorsAndIcons();
+
+ Q_memset( m_TeamIconsSelf, 0, sizeof(m_TeamIconsSelf) );
+ Q_memset( m_TeamIconsDead, 0, sizeof(m_TeamIconsDead) );
+ Q_memset( m_TeamIconsOffscreen, 0, sizeof(m_TeamIconsOffscreen) );
+ Q_memset( m_TeamIconsDeadOffscreen, 0, sizeof(m_TeamIconsDeadOffscreen) );
+
+ m_bombIconPlanted = -1;
+ m_bombIconDropped = -1;
+ m_bombIconCarried = -1;
+ m_bombRingPlanted = -1;
+ m_bombRingDropped = -1;
+ m_bombRingCarried = -1;
+ m_bombRingCarriedOffscreen = -1;
+ m_radioFlash = -1;
+ m_radioFlashOffscreen = -1;
+ m_radarTint = -1;
+ m_hostageFollowing = -1;
+ m_hostageFollowingOffscreen = -1;
+ m_playerFacing = -1;
+ m_cameraIconFirst = -1;
+ m_cameraIconThird = -1;
+ m_cameraIconFree = -1;
+ m_hostageRescueIcon = -1;
+ m_bombSiteIconA = -1;
+ m_bombSiteIconB = -1;
+
+
+ //setup team red
+ m_TeamColors[MAP_ICON_T] = COLOR_RED;
+ m_TeamIcons[MAP_ICON_T] = AddIconTexture( "sprites/player_red_small" );
+ m_TeamIconsSelf[MAP_ICON_T] = AddIconTexture( "sprites/player_red_self" );
+ m_TeamIconsDead[MAP_ICON_T] = AddIconTexture( "sprites/player_red_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_T] = AddIconTexture( "sprites/player_red_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_T] = AddIconTexture( "sprites/player_red_dead_offscreen" );
+
+ // setup team blue
+ m_TeamColors[MAP_ICON_CT] = COLOR_BLUE;
+ m_TeamIcons[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_small" );
+ m_TeamIconsSelf[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_self" );
+ m_TeamIconsDead[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_dead_offscreen" );
+
+ // setup team other
+ m_TeamColors[MAP_ICON_HOSTAGE] = COLOR_GREY;
+ m_TeamIcons[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_small" );
+ m_TeamIconsSelf[MAP_ICON_HOSTAGE] = -1;
+ m_TeamIconsDead[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_dead_offscreen" );
+
+ m_bombIconPlanted = AddIconTexture( "sprites/bomb_planted" );
+ m_bombIconDropped = AddIconTexture( "sprites/bomb_dropped" );
+ m_bombIconCarried = AddIconTexture( "sprites/bomb_carried" );
+
+ m_bombRingPlanted = AddIconTexture( "sprites/bomb_planted_ring" );
+ m_bombRingDropped = AddIconTexture( "sprites/bomb_dropped_ring" );
+ m_bombRingCarried = AddIconTexture( "sprites/bomb_carried_ring" );
+ m_bombRingCarriedOffscreen = AddIconTexture( "sprites/bomb_carried_ring_offscreen" );
+
+ m_hostageFollowing = AddIconTexture( "sprites/hostage_following" );
+ m_hostageFollowingOffscreen = AddIconTexture( "sprites/hostage_following_offscreen" );
+ m_playerFacing = AddIconTexture( "sprites/player_tick" );
+ m_cameraIconFirst = AddIconTexture( "sprites/spectator_eye" );
+ m_cameraIconThird = AddIconTexture( "sprites/spectator_3rdcam" );
+ m_cameraIconFree = AddIconTexture( "sprites/spectator_freecam" );
+ m_hostageRescueIcon = AddIconTexture( "sprites/objective_rescue" );;
+ m_bombSiteIconA = AddIconTexture( "sprites/objective_site_a" );;
+ m_bombSiteIconB = AddIconTexture( "sprites/objective_site_b" );;
+
+ m_radioFlash = AddIconTexture("sprites/player_radio_ring");
+ m_radioFlashOffscreen = AddIconTexture("sprites/player_radio_ring_offscreen");
+
+ m_radarTint = AddIconTexture("sprites/radar_trans");
+
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::ApplySchemeSettings(vgui::IScheme *scheme)
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ m_hIconFont = scheme->GetFont( "DefaultSmall", true );
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::Update( void )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if ( !pPlayer )
+ return;
+
+ int team = pPlayer->GetTeamNumber();
+
+ // if dead with fadetoblack on, we can't show anything
+ if ( mp_fadetoblack.GetBool() && team > TEAM_SPECTATOR && !pPlayer->IsAlive() )
+ {
+ SetMode( MAP_MODE_OFF );
+ return;
+ }
+
+ bool inRadarMode = (GetMode() == MAP_MODE_RADAR);
+ int specmode = pPlayer->GetObserverMode();
+ // if alive, we can only be in radar mode
+ if( !inRadarMode && pPlayer->IsAlive())
+ {
+ SetMode( MAP_MODE_RADAR );
+ inRadarMode = true;
+ }
+
+ if( inRadarMode )
+ {
+ if( specmode > OBS_MODE_DEATHCAM )
+ {
+ // If fully dead, we don't want to be radar any more
+ SetMode( m_playerPreferredMode );
+ m_flChangeSpeed = 0;
+ }
+ else
+ {
+ SetFollowEntity(pPlayer->entindex());
+ UpdatePlayers();
+ }
+ }
+
+ BaseClass::Update();
+
+ if ( GetSpectatorMode() == OBS_MODE_CHASE )
+ {
+ // Follow the local player in chase cam, so the map rotates using the local player's angles
+ SetFollowEntity( pPlayer->entindex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForPlayerIndex( int index )
+{
+ if ( index < 0 || index >= MAX_PLAYERS )
+ return NULL;
+
+ return &m_PlayersCSInfo[ index ];
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForPlayer(MapPlayer_t *player)
+{
+ if( player == NULL )
+ return NULL;
+
+ for( int i = 0; i < MAX_PLAYERS; i++ )
+ {
+ if( &m_Players[i] == player )
+ return &m_PlayersCSInfo[i];
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForHostage(MapPlayer_t *hostage)
+{
+ if( hostage == NULL )
+ return NULL;
+
+ for( int i = 0; i < MAX_HOSTAGES; i++ )
+ {
+ if( &m_Hostages[i] == hostage )
+ return &m_HostagesCSInfo[i];
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+#define TIME_SPOTS_STAY_SEEN (0.5f)
+#define TIME_UNTIL_ENEMY_SEEN (0.5f)
+// rules that define if you can see a player on the overview or not
+bool CCSMapOverview::CanPlayerBeSeen( MapPlayer_t *player )
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if (!localPlayer || !player )
+ return false;
+
+ CSMapPlayer_t *csPlayer = GetCSInfoForPlayer(player);
+
+ if ( !csPlayer )
+ return false;
+
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ // This level will be for all the RadarMode thinking. Base class will be the old way for the other modes.
+ float now = gpGlobals->curtime;
+
+ if( player->position == Vector(0,0,0) )
+ return false; // Invalid guy.
+
+ // draw special icons if within time
+ if ( csPlayer->overrideExpirationTime != -1 && csPlayer->overrideExpirationTime > gpGlobals->curtime )
+ return true;
+
+ // otherwise, not dead people
+ if( player->health <= 0 )
+ return false;
+
+ if( localPlayer->GetTeamNumber() == player->team )
+ return true;// always yes for teammates.
+
+ // and a living enemy needs to have been seen recently, and have been for a while
+ if( csPlayer->timeLastSeen != -1
+ && ( now - csPlayer->timeLastSeen < TIME_SPOTS_STAY_SEEN )
+ && ( now - csPlayer->timeFirstSeen > TIME_UNTIL_ENEMY_SEEN )
+ )
+ return true;
+
+ return false;
+ }
+ else if( player->health <= 0 )
+ {
+ // Have to be under the overriden icon time to draw when dead.
+ if ( csPlayer->overrideExpirationTime == -1 || csPlayer->overrideExpirationTime <= gpGlobals->curtime )
+ return false;
+ }
+
+ return BaseClass::CanPlayerBeSeen(player);
+}
+
+bool CCSMapOverview::CanHostageBeSeen( MapPlayer_t *hostage )
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if ( !localPlayer || !hostage )
+ return false;
+
+
+ CSMapPlayer_t *csHostage = GetCSInfoForHostage(hostage);
+
+ if ( !csHostage )
+ return false;
+
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ // This level will be for all the RadarMode thinking. Base class will be the old way for the other modes.
+ float now = gpGlobals->curtime;
+
+ if( hostage->position == Vector(0,0,0) )
+ return false; // Invalid guy.
+
+ // draw special icons if within time
+ if ( csHostage->overrideExpirationTime != -1 && csHostage->overrideExpirationTime > gpGlobals->curtime )
+ return true;
+
+ // otherwise, not dead people
+ if( hostage->health <= 0 )
+ return false;
+
+ if( localPlayer->GetTeamNumber() == hostage->team )
+ return true;// always yes for teammates.
+
+ // and a living enemy needs to have been seen recently
+ if( csHostage->timeLastSeen != -1 && now - csHostage->timeLastSeen < TIME_SPOTS_STAY_SEEN )
+ return true;
+
+ return false;
+ }
+ else if( hostage->health <= 0 )
+ {
+ // Have to be under the overriden icon time to draw when dead.
+ if ( csHostage->overrideExpirationTime == -1 || csHostage->overrideExpirationTime <= gpGlobals->curtime )
+ return false;
+ }
+
+ return BaseClass::CanPlayerBeSeen(hostage);
+}
+
+CCSMapOverview::CCSMapOverview( const char *pElementName ) : BaseClass( pElementName )
+{
+ m_nRadarMapTextureID = -1;
+
+ g_pMapOverview = this; // for cvars access etc
+
+ // restore non-radar modes
+ switch ( overview_preferred_mode.GetInt() )
+ {
+ case MAP_MODE_INSET:
+ m_playerPreferredMode = MAP_MODE_INSET;
+ break;
+
+ case MAP_MODE_FULL:
+ m_playerPreferredMode = MAP_MODE_FULL;
+ break;
+
+ default:
+ m_playerPreferredMode = MAP_MODE_OFF;
+ break;
+ }
+}
+
+void CCSMapOverview::Init( void )
+{
+ BaseClass::Init();
+
+ // register for events as client listener
+ ListenForGameEvent( "hostage_killed" );
+ ListenForGameEvent( "hostage_rescued" );
+ ListenForGameEvent( "bomb_defused" );
+ ListenForGameEvent( "bomb_exploded" );
+}
+
+CCSMapOverview::~CCSMapOverview()
+{
+ g_pMapOverview = NULL;
+
+ //TODO release Textures ? clear lists
+}
+
+void CCSMapOverview::UpdatePlayers()
+{
+ if( !m_goalIconsLoaded )
+ UpdateGoalIcons();
+
+ UpdateHostages();// Update before players so players can spot them
+
+ UpdateBomb();// Before players so player can properly spot where it is in this update
+
+ UpdateFlashes();
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ float now = gpGlobals->curtime;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+ if( localMapPlayer == NULL )
+ return;
+
+ for ( int i = 1; i<= gpGlobals->maxClients; i++)
+ {
+ MapPlayer_t *player = &m_Players[i-1];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i-1);
+
+ if ( !playerCS )
+ continue;
+
+ // update from global player resources
+ if ( pCSPR->IsConnected(i) )
+ {
+ player->health = pCSPR->GetHealth( i );
+
+ if ( !pCSPR->IsAlive( i ) )
+ {
+ // Safety actually happens after a TKPunish.
+ player->health = 0;
+ playerCS->isDead = true;
+ }
+
+ if ( player->team != pCSPR->GetTeam( i ) )
+ {
+ player->team = pCSPR->GetTeam( i );
+
+ if( player == localMapPlayer )
+ player->icon = m_TeamIconsSelf[ GetIconNumberFromTeamNumber(player->team) ];
+ else
+ player->icon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];
+
+ player->color = m_TeamColors[ GetIconNumberFromTeamNumber(player->team) ];
+ }
+ }
+
+ Vector position = player->position;
+ QAngle angles = player->angle;
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( pPlayer && !pPlayer->IsDormant() )
+ {
+ // update position of active players in our PVS
+ position = pPlayer->EyePosition();
+ angles = pPlayer->EyeAngles();
+
+ SetPlayerPositions( i-1, position, angles );
+ }
+ }
+
+ if ( GetMode() == MAP_MODE_RADAR )
+ {
+ // Check for teammates spotting the bomb
+ if ( m_bomb.state != CSMapBomb_t::BOMB_INVALID && pCSPR->IsBombSpotted() )
+ {
+ SetBombSeen( true );
+ }
+
+ // Check for teammates spotting enemy players
+ for ( int i = 1; i<= gpGlobals->maxClients; ++i )
+ {
+ if ( !pCSPR->IsConnected(i) )
+ continue;
+
+ if ( !pCSPR->IsAlive(i) )
+ continue;
+
+ if ( pCSPR->GetTeam(i) == localMapPlayer->team )
+ continue;
+
+ if ( pCSPR->IsPlayerSpotted(i) )
+ {
+ SetPlayerSeen( i-1 );
+
+ MapPlayer_t *baseEnemy = &m_Players[i-1];
+ if( baseEnemy->health > 0 )
+ {
+ // They were just seen, so if they are alive get rid of their "last known" icon
+ CSMapPlayer_t *csEnemy = GetCSInfoForPlayerIndex(i-1);
+
+ if ( csEnemy )
+ {
+ csEnemy->overrideIcon = -1;
+ csEnemy->overrideIconOffscreen = -1;
+ csEnemy->overridePosition = Vector(0, 0, 0);
+ csEnemy->overrideAngle = QAngle(0, 0, 0);
+ csEnemy->overrideFadeTime = -1;
+ csEnemy->overrideExpirationTime = -1;
+ }
+ }
+ }
+ }
+
+ for( int i = 1; i<= gpGlobals->maxClients; i++ )
+ {
+ MapPlayer_t *player = &m_Players[i-1];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i-1);
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer || !playerCS )
+ continue;
+
+ float timeSinceLastSeen = now - playerCS->timeLastSeen;
+ if( timeSinceLastSeen < 0.25f )
+ continue;
+ if( player->health <= 0 )
+ continue;// We don't need to spot dead guys, since they always show
+ if( player->team == localMapPlayer->team )
+ continue;// We don't need to spot our own guys
+
+ // Now that everyone has had a say on people they can see for us, go through and handle baddies that can no longer be seen.
+ if( playerCS->timeLastSeen != now && player->health > 0 )
+ {
+ // We are not seen now, but if we were seen recently (and for long enough),
+ // put up a "last known" icon and clear timelastseen
+ // if they are alive. Death icon is more important, which is why the health check above.
+ if( timeSinceLastSeen < 0.5f && ( playerCS->timeLastSeen != -1 ) )
+ {
+ if( now - playerCS->timeFirstSeen > TIME_UNTIL_ENEMY_SEEN )
+ {
+ playerCS->overrideIcon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];;
+ playerCS->overrideIconOffscreen = m_TeamIconsOffscreen[ GetIconNumberFromTeamNumber(player->team) ];
+ playerCS->overridePosition = player->position;
+ playerCS->overrideFadeTime = -1;
+ playerCS->overrideExpirationTime = now + LAST_SEEN_ICON_DURATION;
+ playerCS->overrideAngle = player->angle;
+ }
+ playerCS->timeLastSeen = -1;
+ playerCS->timeFirstSeen = -1;
+ }
+ }
+ }
+ }
+}
+
+void CCSMapOverview::UpdateHostages()
+{
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ for( int i=0; i < MAX_HOSTAGES; i++ )
+ {
+ if( pCSPR->IsHostageAlive( i ) )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( pCSPR->GetHostageEntityID(i) );
+ if( hostage == NULL )
+ hostage = &m_Hostages[i];// Don't have entry yet, so need one. This'll only happen once, at start of map
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ if( !hostageCS->isDead )
+ {
+ hostage->index = pCSPR->GetHostageEntityID(i);
+ hostage->position = pCSPR->GetHostagePosition( i );
+ hostage->health = 100; // Hostages don't have health available from pCSPR.
+ hostage->angle = QAngle(0, 0, 0); // No facing, like no health
+ hostage->team = TEAM_CT; // CT in terms of who sees them
+ hostage->icon = m_TeamIcons[ MAP_ICON_HOSTAGE ]; // But hostage for icon.
+ hostage->color = m_TeamColors[ MAP_ICON_HOSTAGE ];
+ hostageCS->isHostage = true;
+
+// engine->Con_NPrintf( i + 15, "ID:%d Pos:(%.0f,%.0f,%.0f)", hostage->index, hostage->position.x, hostage->position.y, hostage->position.z );
+ }
+ else
+ {
+// engine->Con_NPrintf( i + 15, "Mostly Dead" );
+ }
+ }
+ else
+ {
+// engine->Con_NPrintf( i + 15, "Dead" );
+ }
+ }
+}
+
+void CCSMapOverview::UpdateBomb()
+{
+ if( m_bomb.state == CSMapBomb_s::BOMB_GONE )
+ return;// no more updates until map restart
+
+ float now = gpGlobals->curtime;
+
+ // First, decide if it has been too long since the bomb has been seen to clear visibility timers.
+ if( now - m_bomb.timeLastSeen >= TIME_SPOTS_STAY_SEEN && m_bomb.timeFirstSeen != -1 )
+ {
+ SetBombSeen( false );
+ }
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ float biggestRadius = 0, smallestRadius = 0;
+ if ( g_PlantedC4s.Count() > 0 )
+ {
+ // bomb is planted
+ C_PlantedC4 *pC4 = g_PlantedC4s[0];
+
+ if( pC4->IsBombActive() )
+ {
+ m_bomb.position = pC4->GetAbsOrigin();
+ m_bomb.state = CSMapBomb_t::BOMB_PLANTED;
+ m_bomb.ringTravelTime = 3.0f;
+ smallestRadius = m_flIconSize;
+ biggestRadius = m_flIconSize * 15.0f;
+ }
+ else
+ {
+ // Defused or exploded
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ }
+ }
+ else if ( pCSPR->HasC4( 0 ) )
+ {
+ // bomb dropped
+ Vector pos = pCSPR->GetC4Postion();
+
+ if ( pos.x != 0 || pos.y != 0 || pos.z != 0 )
+ {
+ m_bomb.position = pos;
+ m_bomb.state = CSMapBomb_t::BOMB_DROPPED;
+ m_bomb.ringTravelTime = 6.0f;
+ smallestRadius = m_flIconSize;
+ biggestRadius = m_flIconSize * 10.0f;
+ }
+ else
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_INVALID;
+ //Not a bomb map. Man, what a weird system instead of IsBombMap. If nobody has it, and it isn't on the ground, then it isn't a bomb map.
+ }
+ }
+ else
+ {
+ for( int i = 1; i<= gpGlobals->maxClients; i++ )
+ {
+ if( pCSPR->HasC4(i) )
+ {
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer == NULL || pPlayer->IsDormant() )
+ {
+ // Dormant or no player means we are relying on RadarUpdate messages so we can trust the MapOverview position.
+ MapPlayer_t *player = &m_Players[i-1];
+ m_bomb.position = player->position;
+ }
+ else
+ {
+ // Update players is about to put this Real Data in the player sturct, and we don't want the bomb pos lagged one update behind
+ m_bomb.position = pPlayer->GetAbsOrigin();
+ }
+
+ m_bomb.state = CSMapBomb_t::BOMB_CARRIED;
+ m_bomb.ringTravelTime = 0;
+ smallestRadius = m_flIconSize * 1.2f;
+ biggestRadius = m_flIconSize * 1.2f;
+ break;
+ }
+ }
+ }
+
+ int alpha = GetMasterAlpha();
+
+ if( m_bomb.currentRingRadius == m_bomb.maxRingRadius || m_bomb.ringTravelTime == 0 )
+ {
+ m_bomb.currentRingRadius = smallestRadius;
+ m_bomb.maxRingRadius = biggestRadius;
+ m_bomb.currentRingAlpha = alpha;
+ }
+ else
+ {
+ m_bomb.currentRingRadius += (m_bomb.maxRingRadius - m_flIconSize) * gpGlobals->frametime / m_bomb.ringTravelTime;
+ m_bomb.currentRingRadius = MIN( m_bomb.currentRingRadius, m_bomb.maxRingRadius );
+ m_bomb.currentRingAlpha = (alpha - 55) * ((m_bomb.maxRingRadius - m_bomb.currentRingRadius) / (m_bomb.maxRingRadius - m_flIconSize)) + 55;
+ }
+}
+
+bool CCSMapOverview::ShouldDraw( void )
+{
+ int alpha = GetMasterAlpha();
+ if( alpha == 0 )
+ return false;// we have been set to fully transparent
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [smessick] Turn off large map display when in freezecam.
+ //=============================================================================
+ if ( IsInFreezeCam() && GetMode() == MAP_MODE_FULL )
+ {
+ return false;
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ float now = gpGlobals->curtime;
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ if ( (GET_HUDELEMENT( CHudRadar ))->ShouldDraw() == false )
+ {
+ return false;
+ }
+
+ // We have to be alive and not blind to draw in this mode.
+ C_CSPlayer *pCSPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if( !pCSPlayer || pCSPlayer->GetObserverMode() == OBS_MODE_DEATHCAM )
+ {
+ return false;
+ }
+ else if (pCSPlayer->m_flFlashBangTime > now)
+ {
+ return false;
+ }
+ }
+
+ return BaseClass::ShouldDraw();
+}
+
+CCSMapOverview::MapPlayer_t* CCSMapOverview::GetHostageByEntityID( int entityID )
+{
+ for (int i=0; i<MAX_HOSTAGES; i++)
+ {
+ if ( m_Hostages[i].index == entityID )
+ return &m_Hostages[i];
+ }
+
+ return NULL;
+}
+
+CCSMapOverview::MapPlayer_t* CCSMapOverview::GetPlayerByEntityID( int entityID )
+{
+ C_BasePlayer *realPlayer = UTIL_PlayerByIndex(entityID);
+
+ if( realPlayer == NULL )
+ return NULL;
+
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ MapPlayer_t *player = &m_Players[i];
+
+ if ( player->userid == realPlayer->GetUserID() )
+ return player;
+ }
+
+ return NULL;
+}
+
+#define BORDER_WIDTH 4
+bool CCSMapOverview::AdjustPointToPanel(Vector2D *pos)
+{
+ if( pos == NULL )
+ return false;
+
+ int mapInset = GetBorderSize();// This gives us the amount inside the panel that the background is drawing.
+ if( mapInset != 0 )
+ mapInset += BORDER_WIDTH; // And this gives us the border inside the map edge to give us room for offscreen icons.
+
+ int x,y,w,t;
+
+ //MapTpPanel has already offset the x and y. That's why we use 0 for left and top.
+ GetBounds( x,y,w,t );
+
+ bool madeChange = false;
+ if( pos->x < mapInset )
+ {
+ pos->x = mapInset;
+ madeChange = true;
+ }
+ if( pos->x > w - mapInset )
+ {
+ pos->x = w - mapInset;
+ madeChange = true;
+ }
+ if( pos->y < mapInset )
+ {
+ pos->y = mapInset;
+ madeChange = true;
+ }
+ if( pos->y > t - mapInset )
+ {
+ pos->y = t - mapInset;
+ madeChange = true;
+ }
+
+ return madeChange;
+}
+
+void CCSMapOverview::DrawMapTexture()
+{
+ int alpha = GetMasterAlpha();
+
+ if( GetMode() == MAP_MODE_FULL )
+ SetBgColor( Color(0,0,0,0) );// no background in big mode
+ else
+ SetBgColor( Color(0,0,0,alpha * 0.5) );
+
+ int textureIDToUse = m_nMapTextureID;
+ bool foundRadarVersion = false;
+ if( m_nRadarMapTextureID != -1 && GetMode() == MAP_MODE_RADAR )
+ {
+ textureIDToUse = m_nRadarMapTextureID;
+ foundRadarVersion = true;
+ }
+
+ int mapInset = GetBorderSize();
+ int pwidth, pheight;
+ GetSize(pwidth, pheight);
+
+ if ( textureIDToUse > 0 )
+ {
+ // We are drawing to the whole panel with a little border
+ Vector2D panelTL = Vector2D( mapInset, mapInset );
+ Vector2D panelTR = Vector2D( pwidth - mapInset, mapInset );
+ Vector2D panelBR = Vector2D( pwidth - mapInset, pheight - mapInset );
+ Vector2D panelBL = Vector2D( mapInset, pheight - mapInset );
+
+ // So where are those four points on the great big map?
+ Vector2D textureTL = PanelToMap( panelTL );// The top left corner of the display is where on the master map?
+ textureTL /= OVERVIEW_MAP_SIZE;// Texture Vec2D is 0 to 1
+ Vector2D textureTR = PanelToMap( panelTR );
+ textureTR /= OVERVIEW_MAP_SIZE;
+ Vector2D textureBR = PanelToMap( panelBR );
+ textureBR /= OVERVIEW_MAP_SIZE;
+ Vector2D textureBL = PanelToMap( panelBL );
+ textureBL /= OVERVIEW_MAP_SIZE;
+
+ Vertex_t points[4] =
+ {
+ // To draw a textured polygon, the first column is where you want to draw (to), and the second is what you want to draw (from).
+ // We want to draw to the panel (pulled in for a border), and we want to draw the part of the map texture that should be seen.
+ // First column is in panel coords, second column is in 0-1 texture coords
+ Vertex_t( panelTL, textureTL ),
+ Vertex_t( panelTR, textureTR ),
+ Vertex_t( panelBR, textureBR ),
+ Vertex_t( panelBL, textureBL )
+ };
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( textureIDToUse );
+ surface()->DrawTexturedPolygon( 4, points );
+ }
+
+ // If we didn't find the greenscale version of the map, then at least do a tint.
+ if( !foundRadarVersion && GetMode() == MAP_MODE_RADAR )
+ {
+ surface()->DrawSetColor( 0,255,0, alpha / 4 );
+ surface()->DrawFilledRect( mapInset, mapInset, m_vSize.x - 1 - mapInset, m_vSize.y - 1 - mapInset );
+ }
+}
+
+void CCSMapOverview::DrawBomb()
+{
+ if( m_bomb.state == CSMapBomb_t::BOMB_INVALID )
+ return;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+ if( localMapPlayer == NULL )
+ return;
+ float now = gpGlobals->curtime;
+
+ if( localMapPlayer->team == TEAM_CT )
+ {
+ // CT's only get to see it if...
+
+ if( localMapPlayer->health <= 0 )
+ {
+ if ( mp_forcecamera.GetInt() != OBS_ALLOW_ALL )
+ return;// They're dead and spectating isn't restricted
+ }
+ else if( (m_bomb.timeLastSeen == -1)
+ || ( now - m_bomb.timeLastSeen >= TIME_SPOTS_STAY_SEEN )
+ || ( now - m_bomb.timeFirstSeen < TIME_UNTIL_ENEMY_SEEN )
+ )
+ {
+ return;// It's in view
+ }
+ }
+ // else if you aren't CT you can always see it
+
+ int bombIcon;
+ int bombRing;
+ int bombRingOffscreen;
+ switch(m_bomb.state)
+ {
+ case CSMapBomb_t::BOMB_DROPPED:
+ {
+ bombIcon = m_bombIconDropped;
+ bombRing = m_bombRingDropped;
+ bombRingOffscreen = m_bombRingDropped;
+ break;
+ }
+ case CSMapBomb_t::BOMB_CARRIED:
+ {
+ bombIcon = m_bombIconCarried;
+ bombRing = m_bombRingCarried;
+ bombRingOffscreen = m_bombRingCarriedOffscreen;
+ break;
+ }
+ case CSMapBomb_t::BOMB_PLANTED:
+ {
+ bombIcon = m_bombIconPlanted;
+ bombRing = m_bombRingPlanted;
+ bombRingOffscreen = m_bombRingPlanted;
+ break;
+ }
+ case CSMapBomb_t::BOMB_GONE:
+ {
+ bombIcon = m_bombIconPlanted;
+ bombRing = m_bombRingPlanted;
+ bombRingOffscreen = m_bombRingPlanted;
+ break;
+ }
+ default:
+ return;
+ }
+
+ int alpha = 255;
+
+ if( m_bomb.timeGone != -1 && m_bomb.timeFade <= gpGlobals->curtime )
+ alpha *= 1 - ( (float)(gpGlobals->curtime - m_bomb.timeFade) / (float)(m_bomb.timeGone - m_bomb.timeFade) );
+
+ if( m_bomb.state != CSMapBomb_t::BOMB_GONE )
+ DrawIconCS(bombRing, bombRingOffscreen, m_bomb.position, m_bomb.currentRingRadius, 0, m_bomb.currentRingAlpha);
+ DrawIconCS(bombIcon, bombIcon, m_bomb.position, m_flIconSize, 0, alpha);
+}
+
+bool CCSMapOverview::DrawIconCS( int textureID, int offscreenTextureID, Vector pos, float scale, float angle, int alpha, bool allowRotation, const char *text, Color *textColor, float status, Color *statusColor )
+{
+ if( GetMode() == MAP_MODE_RADAR && cl_radaralpha.GetInt() == 0 )
+ return false;
+
+ if( alpha <= 0 )
+ return false;
+
+ Vector2D pospanel = WorldToMap( pos );
+ pospanel = MapToPanel( pospanel );
+
+ int idToUse = textureID;
+ float angleToUse = angle;
+
+ Vector2D oldPos = pospanel;
+ Vector2D adjustment(0,0);
+ if( AdjustPointToPanel( &pospanel ) )
+ {
+ if( offscreenTextureID == -1 )
+ return false; //Doesn't want to draw if off screen.
+
+ // Move it in to on panel, and change the icon.
+ idToUse = offscreenTextureID;
+ // And point towards the original spot
+ adjustment = Vector2D(pospanel.x - oldPos.x, pospanel.y - oldPos.y);
+ QAngle adjustmentAngles;
+ Vector adjustment3D(adjustment.x, -adjustment.y, 0); // Y gets flipped in WorldToMap
+ VectorAngles(adjustment3D, adjustmentAngles) ;
+ if( allowRotation )
+ {
+ // Some icons don't want to rotate even when off radar
+ angleToUse = adjustmentAngles[YAW];
+
+ // And the angle needs to be in world space, not panel space.
+ if( m_bFollowAngle )
+ {
+ angleToUse += m_fViewAngle;
+ }
+ else
+ {
+ if ( m_bRotateMap )
+ angleToUse += 180.0f;
+ else
+ angleToUse += 90.0f;
+ }
+ }
+
+ // Don't draw names for icons that are offscreen (bunches up and looks bad)
+ text = NULL;
+ }
+
+ int d = GetPixelOffset( scale );
+
+ Vector offset;
+
+ offset.x = -scale; offset.y = scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos1 = WorldToMap( pos + offset );
+ Vector2D pos1Panel = MapToPanel(pos1);
+ pos1Panel.x += adjustment.x;
+ pos1Panel.y += adjustment.y;
+
+ offset.x = scale; offset.y = scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos2 = WorldToMap( pos + offset );
+ Vector2D pos2Panel = MapToPanel(pos2);
+ pos2Panel.x += adjustment.x;
+ pos2Panel.y += adjustment.y;
+
+ offset.x = scale; offset.y = -scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos3 = WorldToMap( pos + offset );
+ Vector2D pos3Panel = MapToPanel(pos3);
+ pos3Panel.x += adjustment.x;
+ pos3Panel.y += adjustment.y;
+
+ offset.x = -scale; offset.y = -scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos4 = WorldToMap( pos + offset );
+ Vector2D pos4Panel = MapToPanel(pos4);
+ pos4Panel.x += adjustment.x;
+ pos4Panel.y += adjustment.y;
+
+ Vertex_t points[4] =
+ {
+ Vertex_t( pos1Panel, Vector2D(0,0) ),
+ Vertex_t( pos2Panel, Vector2D(1,0) ),
+ Vertex_t( pos3Panel, Vector2D(1,1) ),
+ Vertex_t( pos4Panel, Vector2D(0,1) )
+ };
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( idToUse );
+ surface()->DrawTexturedPolygon( 4, points );
+
+ pospanel.y += d + 4;
+
+ if ( status >=0.0f && status <= 1.0f && statusColor )
+ {
+ // health bar is 50x3 pixels
+ surface()->DrawSetColor( 0,0,0,255 );
+ surface()->DrawFilledRect( pospanel.x-d, pospanel.y-1, pospanel.x+d, pospanel.y+1 );
+
+ int length = (float)(d*2)*status;
+ surface()->DrawSetColor( statusColor->r(), statusColor->g(), statusColor->b(), 255 );
+ surface()->DrawFilledRect( pospanel.x-d, pospanel.y-1, pospanel.x-d+length, pospanel.y+1 );
+
+ pospanel.y += 3;
+ }
+
+ if ( text && textColor )
+ {
+ wchar_t iconText[ MAX_PLAYER_NAME_LENGTH*2 ];
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( text, iconText, sizeof( iconText ) );
+
+ int wide, tall;
+ surface()->GetTextSize( m_hIconFont, iconText, wide, tall );
+
+ int x = pospanel.x-(wide/2);
+ int y = pospanel.y;
+
+ // draw black shadow text
+ surface()->DrawSetTextColor( 0, 0, 0, 255 );
+ surface()->DrawSetTextPos( x+1, y );
+ surface()->DrawPrintText( iconText, wcslen(iconText) );
+
+ // draw name in color
+ surface()->DrawSetTextColor( textColor->r(), textColor->g(), textColor->b(), 255 );
+ surface()->DrawSetTextPos( x, y );
+ surface()->DrawPrintText( iconText, wcslen(iconText) );
+ }
+
+ return true;
+}
+
+void CCSMapOverview::DrawMapPlayers()
+{
+ DrawGoalIcons();
+ DrawHostages();
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ surface()->DrawSetTextFont( m_hIconFont );
+
+ Color colorGreen( 0, 255, 0, 255 ); // health bar color
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ for (int i=0; i < MAX_PLAYERS; i++)
+ {
+ int alpha = 255;
+ MapPlayer_t *player = &m_Players[i];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i);
+
+ if ( !playerCS )
+ continue;
+
+ if ( !CanPlayerBeSeen( player ) )
+ continue;
+
+ float status = -1;
+ const char *name = NULL;
+
+ if ( m_bShowNames && CanPlayerNameBeSeen( player ) )
+ name = player->name;
+
+ if ( m_bShowHealth && CanPlayerHealthBeSeen( player ) )
+ status = player->health/100.0f;
+
+ // Now draw them
+ if( playerCS->overrideExpirationTime > gpGlobals->curtime )// If dead, an X, if alive, an alpha'd normal icon
+ {
+ int alphaToUse = alpha;
+ if( playerCS->overrideFadeTime != -1 && playerCS->overrideFadeTime <= gpGlobals->curtime )
+ {
+ // Fade linearly from fade start to disappear
+ alphaToUse *= 1 - (float)(gpGlobals->curtime - playerCS->overrideFadeTime) / (float)(playerCS->overrideExpirationTime - playerCS->overrideFadeTime);
+ }
+
+ DrawIconCS( playerCS->overrideIcon, playerCS->overrideIconOffscreen, playerCS->overridePosition, m_flIconSize * 1.1f, GetViewAngle(), player->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &player->color, -1, &colorGreen );
+ if( player->health > 0 )
+ DrawIconCS( m_playerFacing, -1, playerCS->overridePosition, m_flIconSize * 1.1f, playerCS->overrideAngle[YAW], player->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &player->color, status, &colorGreen );
+ }
+ else
+ {
+ float zDifference = 0;
+ if( localPlayer )
+ {
+ if( (localPlayer->GetObserverMode() != OBS_MODE_NONE) && localPlayer->GetObserverTarget() )
+ zDifference = player->position.z - localPlayer->GetObserverTarget()->GetAbsOrigin().z;
+ else
+ zDifference = player->position.z - localPlayer->GetAbsOrigin().z;
+ }
+
+ float sizeForRing = m_flIconSize * 1.4f;
+ float sizeForPlayer = m_flIconSize * 1.1f; // The 1.1 is because the player dots are shrunken a little, so their facing pip can have some space to live
+ if ( zDifference > DIFFERENCE_THRESHOLD )
+ {
+ // A dot above is bigger and a little fuzzy now.
+ sizeForRing *= 1.4f;
+ sizeForPlayer *= 1.4f;
+ alpha *= 0.5f;
+ }
+ else if ( zDifference < -DIFFERENCE_THRESHOLD )
+ {
+ // A dot below is smaller.
+ sizeForRing *= 0.7f;
+ sizeForPlayer *= 0.7f;
+ }
+
+ bool showTalkRing = localPlayer && (localPlayer->GetTeamNumber() == player->team || localPlayer->GetTeamNumber() == TEAM_SPECTATOR);
+
+ if( showTalkRing && playerCS->currentFlashAlpha > 0 )// Flash type
+ {
+ // Make them flash a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, player->position, sizeForRing, player->angle[YAW], playerCS->currentFlashAlpha);
+ }
+ else if( showTalkRing && pCSPR->IsAlive( i + 1 ) && GetClientVoiceMgr()->IsPlayerSpeaking( i + 1) ) // Or solid on type
+ {
+ // Make them show a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, player->position, sizeForRing, player->angle[YAW], 255);
+ }
+
+ bool doingLocalPlayer = GetPlayerByUserID(localPlayer->GetUserID()) == player;
+ float angleForPlayer = GetViewAngle();
+
+ if( doingLocalPlayer )
+ {
+ sizeForPlayer *= 4.0f; // The self icon is really big since it has a camera view cone attached.
+ angleForPlayer = player->angle[YAW];// And, the self icon now rotates, natch.
+ }
+
+ int offscreenIcon = m_TeamIconsOffscreen[GetIconNumberFromTeamNumber(player->team)];
+ DrawIconCS( player->icon, offscreenIcon, player->position, sizeForPlayer, angleForPlayer, alpha, true, name, &player->color, status, &colorGreen );
+ if( !doingLocalPlayer )
+ {
+ // Draw the facing for everyone but the local player.
+ if( player->health > 0 )
+ DrawIconCS( m_playerFacing, -1, player->position, sizeForPlayer, player->angle[YAW], alpha, true, name, &player->color, status, &colorGreen );
+ }
+ }
+ }
+
+ DrawBomb();// After players so it can draw on top
+}
+
+void CCSMapOverview::DrawHostages()
+{
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ surface()->DrawSetTextFont( m_hIconFont );
+
+ Color colorGreen( 0, 255, 0, 255 ); // health bar color
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ for (int i=0; i < MAX_HOSTAGES; i++)
+ {
+ int alpha = 255;
+ MapPlayer_t *hostage = GetHostageByEntityID( pCSPR->GetHostageEntityID(i) );
+ if( hostage == NULL )
+ continue;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ continue;
+
+ if ( !CanHostageBeSeen( hostage ) )
+ {
+// engine->Con_NPrintf( i + 30, "Can't be seen." );
+ continue;
+ }
+
+ float status = -1;
+ const char *name = NULL;
+
+ if( hostageCS->overrideExpirationTime > gpGlobals->curtime )// If dead, an X, if alive, an alpha'd normal icon
+ {
+// engine->Con_NPrintf( i + 30, "ID:%d Override Pos:(%.0f,%.0f,%.0f)", hostage->index, hostageCS->overridePosition.x, hostageCS->overridePosition.y, hostageCS->overridePosition.z );
+ int alphaToUse = alpha;
+ if( hostageCS->overrideFadeTime != -1 && hostageCS->overrideFadeTime <= gpGlobals->curtime )
+ {
+ // Fade linearly from fade start to disappear
+ alphaToUse *= 1 - (float)(gpGlobals->curtime - hostageCS->overrideFadeTime) / (float)(hostageCS->overrideExpirationTime - hostageCS->overrideFadeTime);
+ }
+
+ DrawIconCS( hostageCS->overrideIcon, hostageCS->overrideIconOffscreen, hostageCS->overridePosition, m_flIconSize, hostageCS->overrideAngle[YAW], hostage->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &hostage->color, status, &colorGreen );
+ }
+ else
+ {
+ if( localPlayer && localPlayer->GetTeamNumber() == hostage->team && hostageCS->currentFlashAlpha > 0 )
+ {
+ // Make them flash a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, hostage->position, m_flIconSize * 1.4f, hostage->angle[YAW], hostageCS->currentFlashAlpha);
+ }
+
+// engine->Con_NPrintf( i + 30, "ID:%d Pos:(%.0f,%.0f,%.0f)", hostage->index, hostage->position.x, hostage->position.y, hostage->position.z );
+ int normalIcon, offscreenIcon;
+ float zDifference = 0;
+ if( localPlayer )
+ {
+ if( (localPlayer->GetObserverMode() != OBS_MODE_NONE) && localPlayer->GetObserverTarget() )
+ zDifference = hostage->position.z - localPlayer->GetObserverTarget()->GetAbsOrigin().z;
+ else
+ zDifference = hostage->position.z - localPlayer->GetAbsOrigin().z;
+ }
+
+ float sizeForHostage = m_flIconSize;
+ if( zDifference > DIFFERENCE_THRESHOLD )
+ {
+ // A dot above is bigger and a little fuzzy now.
+ sizeForHostage = m_flIconSize * 1.5f;
+ alpha *= 0.5f;
+ }
+ else if( zDifference < -DIFFERENCE_THRESHOLD )
+ {
+ // A dot below is smaller.
+ sizeForHostage = m_flIconSize * 0.6f;
+ }
+
+ normalIcon = hostage->icon;
+ offscreenIcon = m_TeamIconsOffscreen[ MAP_ICON_HOSTAGE ];
+ DrawIconCS( normalIcon, offscreenIcon, hostage->position, sizeForHostage, GetViewAngle(), alpha, true, name, &hostage->color, status, &colorGreen );
+
+ if( pCSPR->IsHostageFollowingSomeone( i ) )
+ {
+ // If they are following a CT, then give them a little extra symbol to show it.
+ DrawIconCS( m_hostageFollowing, m_hostageFollowingOffscreen, hostage->position, sizeForHostage, hostage->angle[YAW], alpha );
+ }
+ }
+ }
+}
+void CCSMapOverview::SetMap(const char * levelname)
+{
+ BaseClass::SetMap(levelname);
+
+ int wide, tall;
+ surface()->DrawGetTextureSize( m_nMapTextureID, wide, tall );
+ if( wide == 0 && tall == 0 )
+ {
+ m_nMapTextureID = -1;
+ m_nRadarMapTextureID = -1;
+ return;// No map image, so no radar image
+ }
+
+ char radarFileName[MAX_PATH];
+ Q_snprintf(radarFileName, MAX_PATH, "%s_radar", m_MapKeyValues->GetString("material"));
+ m_nRadarMapTextureID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile(m_nRadarMapTextureID, radarFileName, true, false);
+ int radarWide = -1;
+ int radarTall = -1;
+ surface()->DrawGetTextureSize(m_nRadarMapTextureID, radarWide, radarTall);
+ bool radarTextureFound = false;
+ if( radarWide == wide && radarTall == tall )
+ {
+ // Unbelievable that these is no failure return from SetTextureFile, and not
+ // even a ValidTexture check on the ID. So I can check if it is different from
+ // the original. It'll be a 32x32 default if not present.
+ radarTextureFound = true;
+ }
+
+ if( !radarTextureFound )
+ {
+ if( !CreateRadarImage(m_MapKeyValues->GetString("material"), radarFileName) )
+ m_nRadarMapTextureID = -1;
+ }
+
+ ClearGoalIcons();
+}
+
+bool CCSMapOverview::CreateRadarImage(const char *mapName, const char * radarFileName)
+{
+#ifdef GENERATE_RADAR_FILE
+ char fullFileName[MAX_PATH];
+ Q_snprintf(fullFileName, MAX_PATH, "materials/%s.vtf", mapName);
+ char fullRadarFileName[MAX_PATH];
+ Q_snprintf(fullRadarFileName, MAX_PATH, "materials/%s.vtf", radarFileName);
+
+ // Not found, so try to make one
+ FileHandle_t fp;
+ fp = ::filesystem->Open( fullFileName, "rb" );
+ if( !fp )
+ {
+ return false;
+ }
+ ::filesystem->Seek( fp, 0, FILESYSTEM_SEEK_TAIL );
+ int srcVTFLength = ::filesystem->Tell( fp );
+ ::filesystem->Seek( fp, 0, FILESYSTEM_SEEK_HEAD );
+
+ CUtlBuffer buf;
+ buf.EnsureCapacity( srcVTFLength );
+ int overviewMapBytesRead = ::filesystem->Read( buf.Base(), srcVTFLength, fp );
+ ::filesystem->Close( fp );
+
+ buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );// Need to set these explicitly since ->Read goes straight to memory and skips them.
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, overviewMapBytesRead );
+
+ IVTFTexture *radarTexture = CreateVTFTexture();
+ if (radarTexture->Unserialize(buf))
+ {
+ ImageFormat oldImageFormat = radarTexture->Format();
+ radarTexture->ConvertImageFormat(IMAGE_FORMAT_RGBA8888, false);
+ unsigned char *imageData = radarTexture->ImageData(0,0,0);
+ int size = radarTexture->ComputeTotalSize(); // in bytes!
+ unsigned char *pEnd = imageData + size;
+
+ for( ; imageData < pEnd; imageData += 4 )
+ {
+ imageData[0] = 0; // R
+ imageData[2] = 0; // B
+ }
+
+ radarTexture->ConvertImageFormat(oldImageFormat, false);
+
+ buf.Clear();
+ radarTexture->Serialize(buf);
+
+ fp = ::filesystem->Open(fullRadarFileName, "wb");
+ ::filesystem->Write(buf.Base(), buf.TellPut(), fp);
+ ::filesystem->Close(fp);
+ DestroyVTFTexture(radarTexture);
+ buf.Purge();
+
+ // And need a vmt file to go with it.
+ char vmtFilename[MAX_PATH];
+ Q_snprintf(vmtFilename, MAX_PATH, "%s", fullRadarFileName);
+ char *extension = &vmtFilename[Q_strlen(vmtFilename) - 3];
+ *extension++ = 'v';
+ *extension++ = 'm';
+ *extension++ = 't';
+ *extension++ = '\0';
+ fp = ::filesystem->Open(vmtFilename, "wt");
+ ::filesystem->Write("\"UnlitGeneric\"\n", 15, fp);
+ ::filesystem->Write("{\n", 2, fp);
+ ::filesystem->Write("\t\"$translucent\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$basetexture\" \"", 17, fp);
+ ::filesystem->Write(radarFileName, Q_strlen(radarFileName), fp);
+ ::filesystem->Write("\"\n", 2, fp);
+ ::filesystem->Write("\t\"$vertexalpha\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$vertexcolor\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$no_fullbright\" \"1\"\n", 22, fp);
+ ::filesystem->Write("\t\"$ignorez\" \"1\"\n", 16, fp);
+ ::filesystem->Write("}\n", 2, fp);
+ ::filesystem->Close(fp);
+
+ m_nRadarMapTextureID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_nRadarMapTextureID, radarFileName, true, true);
+ return true;
+ }
+#endif
+ return false;
+}
+
+void CCSMapOverview::ResetRound()
+{
+ BaseClass::ResetRound();
+
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ CSMapPlayer_t *p = &m_PlayersCSInfo[i];
+
+ p->isDead = false;
+
+ p->overrideFadeTime = -1;
+ p->overrideExpirationTime = -1;
+ p->overrideIcon = -1;
+ p->overrideIconOffscreen = -1;
+ p->overridePosition = Vector( 0, 0, 0);
+ p->overrideAngle = QAngle(0, 0, 0);
+
+ p->timeLastSeen = -1;
+ p->timeFirstSeen = -1;
+ p->isHostage = false;
+
+ p->flashUntilTime = -1;
+ p->nextFlashPeakTime = -1;
+ p->currentFlashAlpha = 0;
+ }
+
+ for (int i=0; i<MAX_HOSTAGES; i++)
+ {
+ MapPlayer_t *basep = &m_Hostages[i];
+ CSMapPlayer_t *p = &m_HostagesCSInfo[i];
+
+ basep->health = 100;
+ Q_memset( basep->trail, 0, sizeof(basep->trail) );
+ basep->position = Vector( 0, 0, 0 );
+ basep->index = 0;
+
+ p->isDead = false;
+
+ p->overrideFadeTime = -1;
+ p->overrideExpirationTime = -1;
+ p->overrideIcon = -1;
+ p->overrideIconOffscreen = -1;
+ p->overridePosition = Vector( 0, 0, 0);
+ p->overrideAngle = QAngle(0, 0, 0);
+
+ p->timeLastSeen = -1;
+ p->timeFirstSeen = -1;
+ p->isHostage = false;
+
+ p->flashUntilTime = -1;
+ p->nextFlashPeakTime = -1;
+ p->currentFlashAlpha = 0;
+ }
+
+ m_bomb.position = Vector(0,0,0);
+ m_bomb.state = CSMapBomb_t::BOMB_INVALID;
+ m_bomb.timeLastSeen = -1;
+ m_bomb.timeFirstSeen = -1;
+ m_bomb.timeFade = -1;
+ m_bomb.timeGone = -1;
+
+ m_bomb.currentRingRadius = -1;
+ m_bomb.currentRingAlpha = -1;
+ m_bomb.maxRingRadius = -1;
+ m_bomb.ringTravelTime = -1;
+
+ m_goalIconsLoaded = false;
+}
+
+void CCSMapOverview::DrawCamera()
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if (!localPlayer)
+ return;
+
+ if( localPlayer->GetObserverMode() == OBS_MODE_ROAMING )
+ {
+ // Instead of the programmer-art red dot, we'll draw an icon for when our camera is roaming.
+ int alpha = 255;
+ DrawIconCS(m_cameraIconFree, m_cameraIconFree, localPlayer->GetAbsOrigin(), m_flIconSize * 3.0f, localPlayer->EyeAngles()[YAW], alpha);
+ }
+ else if( localPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
+ {
+ if( localPlayer->GetObserverTarget() )
+ {
+ // Fade it if it is on top of a player dot. And don't rotate it.
+ int alpha = 255 * 0.5f;
+ DrawIconCS(m_cameraIconFirst, m_cameraIconFirst, localPlayer->GetObserverTarget()->GetAbsOrigin(), m_flIconSize * 1.5f, GetViewAngle(), alpha);
+ }
+ }
+ else if( localPlayer->GetObserverMode() == OBS_MODE_CHASE )
+ {
+ if( localPlayer->GetObserverTarget() )
+ {
+ // Or Draw the third-camera a little bigger. (Needs room to be off the dot being followed)
+ int alpha = 255;
+ DrawIconCS(m_cameraIconThird, m_cameraIconThird, localPlayer->GetObserverTarget()->GetAbsOrigin(), m_flIconSize * 3.0f, localPlayer->EyeAngles()[YAW], alpha);
+ }
+ }
+}
+
+void CCSMapOverview::FireGameEvent( IGameEvent *event )
+{
+ const char * type = event->GetName();
+
+ if ( Q_strcmp(type,"hostage_killed") == 0 )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( event->GetInt("hostage") );
+
+// DevMsg("Hostage id %d just died.\n", event->GetInt("hostage"));
+
+ if ( !hostage )
+ return;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ hostage->health = 0;
+ hostageCS->isDead = true;
+ Q_memset( hostage->trail, 0, sizeof(hostage->trail) ); // clear trails
+
+ hostageCS->overrideIcon = m_TeamIconsDead[MAP_ICON_HOSTAGE];
+ hostageCS->overrideIconOffscreen = hostageCS->overrideIcon;
+ hostageCS->overridePosition = hostage->position;
+ hostageCS->overrideAngle = hostage->angle;
+ hostageCS->overrideFadeTime = gpGlobals->curtime + DEATH_ICON_FADE;
+ hostageCS->overrideExpirationTime = gpGlobals->curtime + DEATH_ICON_DURATION;
+ }
+ else if ( Q_strcmp(type,"hostage_rescued") == 0 )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( event->GetInt("hostage") );
+
+// DevMsg("Hostage id %d just got rescued.\n", event->GetInt("hostage"));
+
+ if ( !hostage )
+ return;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ hostage->health = 0;
+ hostageCS->isDead = true;
+ Q_memset( hostage->trail, 0, sizeof(hostage->trail) ); // clear trails
+
+ hostageCS->overrideIcon = hostage->icon;
+ hostageCS->overrideIconOffscreen = -1;
+ hostageCS->overridePosition = hostage->position;
+ hostageCS->overrideAngle = hostage->angle;
+ hostageCS->overrideFadeTime = gpGlobals->curtime;
+ hostageCS->overrideExpirationTime = gpGlobals->curtime + HOSTAGE_RESCUE_DURATION;
+ }
+ else if ( Q_strcmp(type,"bomb_defused") == 0 )
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ m_bomb.timeFade = gpGlobals->curtime;
+ m_bomb.timeGone = gpGlobals->curtime + BOMB_FADE_DURATION;
+ }
+ else if ( Q_strcmp(type,"bomb_exploded") == 0 )
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ m_bomb.timeFade = gpGlobals->curtime;
+ m_bomb.timeGone = gpGlobals->curtime + BOMB_FADE_DURATION;
+ }
+ else if ( Q_strcmp(type,"player_death") == 0 )
+ {
+ MapPlayer_t *player = GetPlayerByUserID( event->GetInt("userid") );
+
+ if ( !player )
+ return;
+
+ player->health = 0;
+ Q_memset( player->trail, 0, sizeof(player->trail) ); // clear trails
+
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayer(player);
+
+ if ( !playerCS )
+ return;
+
+ playerCS->isDead = true;
+ playerCS->overrideIcon = m_TeamIconsDead[GetIconNumberFromTeamNumber(player->team)];
+ playerCS->overrideIconOffscreen = playerCS->overrideIcon;
+ playerCS->overridePosition = player->position;
+ playerCS->overrideAngle = player->angle;
+ playerCS->overrideFadeTime = gpGlobals->curtime + DEATH_ICON_FADE;
+ playerCS->overrideExpirationTime = gpGlobals->curtime + DEATH_ICON_DURATION;
+ }
+ else if ( Q_strcmp(type,"player_team") == 0 )
+ {
+ MapPlayer_t *player = GetPlayerByUserID( event->GetInt("userid") );
+
+ if ( !player )
+ return;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+
+ player->team = event->GetInt("team");
+
+ if( player == localMapPlayer )
+ player->icon = m_TeamIconsSelf[ GetIconNumberFromTeamNumber(player->team) ];
+ else
+ player->icon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];
+
+ player->color = m_TeamColors[ GetIconNumberFromTeamNumber(player->team) ];
+ }
+ else
+ {
+ BaseClass::FireGameEvent(event);
+ }
+}
+
+void CCSMapOverview::SetMode(int mode)
+{
+ if ( mode == MAP_MODE_RADAR )
+ {
+ m_flChangeSpeed = 0; // change size instantly
+ // We want the _output_ of the radar to be consistant, so we need to take the map scale in to account.
+ float desiredZoom = (DESIRED_RADAR_RESOLUTION * m_fMapScale) / (OVERVIEW_MAP_SIZE * m_fFullZoom);
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0, 0, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ if( CBasePlayer::GetLocalPlayer() )
+ SetFollowEntity( CBasePlayer::GetLocalPlayer()->entindex() );
+
+ SetPaintBackgroundType( 2 );// rounded corners
+ ShowPanel( true );
+ }
+ else if ( mode == MAP_MODE_INSET )
+ {
+ SetPaintBackgroundType( 2 );// rounded corners
+
+ float desiredZoom = (overview_preferred_view_size.GetFloat() * m_fMapScale) / (OVERVIEW_MAP_SIZE * m_fFullZoom);
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+ else
+ {
+ SetPaintBackgroundType( 0 );// square corners
+
+ float desiredZoom = 1.0f;
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ BaseClass::SetMode(mode);
+}
+
+void CCSMapOverview::UpdateSizeAndPosition()
+{
+ int x,y,w,h;
+
+ vgui::surface()->GetScreenSize( w, h );
+
+ switch( m_nMode )
+ {
+ case MAP_MODE_RADAR:
+ {
+ // To allow custom hud scripts to work, get our size from the HudRadar element that people already tweak.
+ int x, y, w, t;
+ (GET_HUDELEMENT( CHudRadar ))->GetBounds(x, y, w, t);
+ m_vPosition.x = x;
+ m_vPosition.y = y;
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ }
+
+ m_vSize.x = w;
+ m_vSize.y = w;// Intentionally not 't'. We need to enforce square-ness to prevent people from seeing more of the map by fiddling their HudLayout
+ break;
+ }
+
+ case MAP_MODE_INSET:
+ {
+ m_vPosition.x = XRES(16);
+ m_vPosition.y = YRES(16);
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ }
+
+ m_vSize.x = w/4;
+ m_vSize.y = m_vSize.x/1.333;
+ break;
+ }
+
+ case MAP_MODE_FULL:
+ default:
+ {
+ m_vSize.x = w;
+ m_vSize.y = h;
+
+ m_vPosition.x = 0;
+ m_vPosition.y = 0;
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ m_vSize.y -= g_pSpectatorGUI->GetTopBarHeight();
+ m_vSize.y -= g_pSpectatorGUI->GetBottomBarHeight();
+ }
+ break;
+ }
+ }
+
+ GetBounds( x,y,w,h );
+
+ if ( m_flChangeSpeed > 0 )
+ {
+ // adjust slowly
+ int pixels = m_flChangeSpeed * gpGlobals->frametime;
+ x = AdjustValue( x, m_vPosition.x, pixels );
+ y = AdjustValue( y, m_vPosition.y, pixels );
+ w = AdjustValue( w, m_vSize.x, pixels );
+ h = AdjustValue( h, m_vSize.y, pixels );
+ }
+ else
+ {
+ // set instantly
+ x = m_vPosition.x;
+ y = m_vPosition.y;
+ w = m_vSize.x;
+ h = m_vSize.y;
+ }
+
+ SetBounds( x,y,w,h );
+}
+
+void CCSMapOverview::SetPlayerSeen( int index )
+{
+ CSMapPlayer_t *pCS = GetCSInfoForPlayerIndex(index);
+
+ float now = gpGlobals->curtime;
+
+ if( pCS )
+ {
+ if( pCS->timeLastSeen == -1 )
+ pCS->timeFirstSeen = now;
+
+ pCS->timeLastSeen = now;
+ }
+}
+
+void CCSMapOverview::SetBombSeen( bool seen )
+{
+ if( seen )
+ {
+ float now = gpGlobals->curtime;
+
+ if( m_bomb.timeLastSeen == -1 )
+ m_bomb.timeFirstSeen = now;
+
+ m_bomb.timeLastSeen = now;
+ }
+ else
+ {
+ m_bomb.timeFirstSeen = -1;
+ m_bomb.timeLastSeen = -1;
+ }
+}
+
+void CCSMapOverview::FlashEntity( int entityID )
+{
+ MapPlayer_t *player = GetPlayerByEntityID(entityID);
+ if( player == NULL )
+ return;
+
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayer(player);
+
+ if ( !playerCS )
+ return;
+
+ playerCS->flashUntilTime = gpGlobals->curtime + 2.0f;
+ playerCS->currentFlashAlpha = 255;
+ playerCS->nextFlashPeakTime = gpGlobals->curtime + 0.5f;
+}
+
+void CCSMapOverview::UpdateFlashes()
+{
+ float now = gpGlobals->curtime;
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i);
+ if( playerCS->flashUntilTime <= now )
+ {
+ // Flashing over.
+ playerCS->currentFlashAlpha = 0;
+ }
+ else
+ {
+ if( playerCS->nextFlashPeakTime <= now )
+ {
+ // Time for a peak
+ playerCS->currentFlashAlpha = 255;
+ playerCS->nextFlashPeakTime = now + 0.5f;
+ playerCS->nextFlashPeakTime = MIN( playerCS->nextFlashPeakTime, playerCS->flashUntilTime );
+ }
+ else
+ {
+ // Just fade away
+ playerCS->currentFlashAlpha -= ((playerCS->currentFlashAlpha * gpGlobals->frametime) / (playerCS->nextFlashPeakTime - now));
+ playerCS->currentFlashAlpha = MAX( 0, playerCS->currentFlashAlpha );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::SetPlayerPreferredMode( int mode )
+{
+ // A player has given an explicit overview_mode command, so we need to honor that when we are done being the radar.
+ m_playerPreferredMode = mode;
+
+ // save off non-radar preferred modes
+ switch ( mode )
+ {
+ case MAP_MODE_OFF:
+ overview_preferred_mode.SetValue( MAP_MODE_OFF );
+ break;
+
+ case MAP_MODE_INSET:
+ overview_preferred_mode.SetValue( MAP_MODE_INSET );
+ break;
+
+ case MAP_MODE_FULL:
+ overview_preferred_mode.SetValue( MAP_MODE_FULL );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::SetPlayerPreferredViewSize( float viewSize )
+{
+ overview_preferred_view_size.SetValue( viewSize );
+}
+
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetIconNumberFromTeamNumber( int teamNumber )
+{
+ switch(teamNumber)
+ {
+ case TEAM_TERRORIST:
+ return MAP_ICON_T;
+
+ case TEAM_CT:
+ return MAP_ICON_CT;
+
+ default:
+ return MAP_ICON_HOSTAGE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::ClearGoalIcons()
+{
+ m_goalIcons.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::UpdateGoalIcons()
+{
+ // The goal entities don't exist on the client, so we have to get them from the CS Resource.
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ Vector bombA = pCSPR->GetBombsiteAPosition();
+ if( bombA != vec3_origin )
+ {
+ CSMapGoal_t bombGoalA;
+ bombGoalA.position = bombA;
+ bombGoalA.iconToUse = m_bombSiteIconA;
+ m_goalIcons.AddToTail( bombGoalA );
+ m_goalIconsLoaded = true;
+ }
+
+ Vector bombB = pCSPR->GetBombsiteBPosition();
+ if( bombB != vec3_origin )
+ {
+ CSMapGoal_t bombGoalB;
+ bombGoalB.position = bombB;
+ bombGoalB.iconToUse = m_bombSiteIconB;
+ m_goalIcons.AddToTail( bombGoalB );
+ m_goalIconsLoaded = true;
+ }
+
+ for( int rescueIndex = 0; rescueIndex < MAX_HOSTAGE_RESCUES; rescueIndex++ )
+ {
+ Vector hostageI = pCSPR->GetHostageRescuePosition( rescueIndex );
+ if( hostageI != vec3_origin )
+ {
+ CSMapGoal_t hostageGoalI;
+ hostageGoalI.position = hostageI;
+ hostageGoalI.iconToUse = m_hostageRescueIcon;
+ m_goalIcons.AddToTail( hostageGoalI );
+ m_goalIconsLoaded = true;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::DrawGoalIcons()
+{
+ for( int iconIndex = 0; iconIndex < m_goalIcons.Count(); iconIndex++ )
+ {
+ // Goal icons are drawn without turning, but with edge adjustment.
+ CSMapGoal_t *currentIcon = &(m_goalIcons[iconIndex]);
+ int alpha = 255;
+ DrawIconCS(currentIcon->iconToUse, currentIcon->iconToUse, currentIcon->position, m_flIconSize, GetViewAngle(), alpha, false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CCSMapOverview::IsRadarLocked()
+{
+ return cl_radar_locked.GetBool();
+}
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetMasterAlpha( void )
+{
+ // The master alpha is the alpha that the map wants to draw at. The background will be at half that, and the icons
+ // will always be full. (The icons fade themselves for functional reasons like seen-recently.)
+ int alpha = 255;
+ if( GetMode() == MAP_MODE_RADAR )
+ alpha = cl_radaralpha.GetInt();
+ else
+ alpha = overview_alpha.GetFloat() * 255;
+ alpha = clamp( alpha, 0, 255 );
+
+ return alpha;
+}
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetBorderSize( void )
+{
+ switch( GetMode() )
+ {
+ case MAP_MODE_RADAR:
+ return 4;
+ case MAP_MODE_INSET:
+ return 4;
+ case MAP_MODE_FULL:
+ default:
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+Vector2D CCSMapOverview::PanelToMap( const Vector2D &panelPos )
+{
+ // This is the reversing of baseclass's MapToPanel
+ int pwidth, pheight;
+ GetSize(pwidth, pheight);
+ float viewAngle = GetViewAngle();
+ float fScale = (m_fZoom * m_fFullZoom) / OVERVIEW_MAP_SIZE;
+
+ Vector offset;
+ offset.x = (panelPos.x - (pwidth * 0.5f)) / pheight;
+ offset.y = (panelPos.y - (pheight * 0.5f)) / pheight;
+
+ offset.x /= fScale;
+ offset.y /= fScale;
+
+ VectorYawRotate( offset, -viewAngle, offset );
+
+ Vector2D mapPos;
+ mapPos.x = offset.x + m_MapCenter.x;
+ mapPos.y = offset.y + m_MapCenter.y;
+
+ return mapPos;
+}
diff --git a/game/client/cstrike/VGUI/cstrikespectatorgui.h b/game/client/cstrike/VGUI/cstrikespectatorgui.h
new file mode 100644
index 0000000..5064812
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikespectatorgui.h
@@ -0,0 +1,279 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSSPECTATORGUI_H
+#define CSSPECTATORGUI_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "spectatorgui.h"
+#include "mapoverview.h"
+#include "cs_shareddefs.h"
+
+extern ConVar mp_playerid; // in cs_gamerules.h
+extern ConVar mp_forcecamera; // in gamevars_shared.h
+extern ConVar mp_fadetoblack;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Cstrike Spectator UI
+//-----------------------------------------------------------------------------
+class CCSSpectatorGUI : public CSpectatorGUI
+{
+private:
+ DECLARE_CLASS_SIMPLE( CCSSpectatorGUI, CSpectatorGUI );
+
+public:
+ CCSSpectatorGUI( IViewPort *pViewPort );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ virtual void UpdateSpectatorPlayerList( void );
+ virtual void Update( void );
+ virtual bool NeedsUpdate( void );
+ //=============================================================================
+ // HPE_BEGIN:
+ // [smessick]
+ //=============================================================================
+ virtual void ShowPanel( bool bShow );
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+protected:
+
+ void UpdateTimer();
+ void UpdateAccount();
+
+ int m_nLastAccount;
+ int m_nLastTime;
+ int m_nLastSpecMode;
+ CBaseEntity *m_nLastSpecTarget;
+
+ void StoreWidths( void );
+ void ResizeControls( void );
+ bool ControlsPresent( void ) const;
+
+ vgui::Label *m_pCTLabel;
+ vgui::Label *m_pCTScore;
+ vgui::Label *m_pTerLabel;
+ vgui::Label *m_pTerScore;
+ vgui::Label *m_pTimer;
+ vgui::Label *m_pTimerLabel;
+ vgui::Panel *m_pDivider;
+ vgui::Label *m_pExtraInfo;
+
+ bool m_modifiedWidths;
+
+ int m_scoreWidth;
+ int m_extraInfoWidth;
+};
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+#define DESIRED_RADAR_RESOLUTION 450
+
+class CCSMapOverview : public CMapOverview
+{
+ DECLARE_CLASS_SIMPLE( CCSMapOverview, CMapOverview );
+
+public:
+
+ enum
+ {
+ MAP_ICON_T = 0,
+ MAP_ICON_CT,
+ MAP_ICON_HOSTAGE,
+ MAP_ICON_COUNT
+ };
+
+ CCSMapOverview( const char *pElementName );
+ virtual ~CCSMapOverview();
+
+ virtual bool ShouldDraw( void );
+ vgui::Panel *GetAsPanel(){ return this; }
+ virtual bool AllowConCommandsWhileAlive(){return false;}
+ virtual void SetPlayerPreferredMode( int mode );
+ virtual void SetPlayerPreferredViewSize( float viewSize );
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+
+protected: // private structures & types
+
+ // list of game events the hLTV takes care of
+
+ typedef struct {
+ int xpos;
+ int ypos;
+ } FootStep_t;
+
+ // Extra stuff in a this-level parallel array
+ typedef struct CSMapPlayer_s {
+ int overrideIcon; // if not -1, the icon to use instead
+ int overrideIconOffscreen; // to use with overrideIcon
+ float overrideFadeTime; // Time to start fading the override icon
+ float overrideExpirationTime; // Time to not use the override icon any more
+ Vector overridePosition; // Where the overridden icon will draw
+ QAngle overrideAngle; // And at what angle
+ bool isDead; // Death latch, since client can be behind the times on health messages.
+ float timeLastSeen; // curtime that we last saw this guy.
+ float timeFirstSeen; // curtime that we started seeing this guy
+ bool isHostage; // Not a full player, a hostage. Special icon, different death event
+ float flashUntilTime;
+ float nextFlashPeakTime;
+ int currentFlashAlpha;
+ } CSMapPlayer_t;
+
+ typedef struct CSMapBomb_s
+ {
+ Vector position;
+
+ enum BombState
+ {
+ BOMB_PLANTED, //planted and ticking down
+ BOMB_DROPPED, //dropped and lying loose
+ BOMB_CARRIED, //in the arms of a player
+ BOMB_GONE, //defused or exploded, but was planted
+ BOMB_INVALID //no bomb
+ };
+ BombState state;
+
+ float timeLastSeen;
+ float timeFirstSeen;
+ float timeFade;
+ float timeGone;
+
+ float currentRingRadius;
+ float currentRingAlpha;
+ float maxRingRadius;
+ float ringTravelTime;
+ } CSMapBomb_t;
+
+ typedef struct CSMapGoal_s
+ {
+ Vector position;
+ int iconToUse;
+ } CSMapGoal_t;
+
+public: // IViewPortPanel interface:
+
+ virtual void Update();
+ virtual void Init( void );
+
+ // both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
+ vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
+ virtual bool IsVisible() { return BaseClass::IsVisible(); }
+ virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); }
+
+ // IGameEventListener
+
+ virtual void FireGameEvent( IGameEvent *event);
+
+ // VGUI overrides
+
+ // Player settings:
+ void SetPlayerSeen( int index );
+ void SetBombSeen( bool seen );
+
+ // general settings:
+ virtual void SetMap(const char * map);
+ virtual void SetMode( int mode );
+
+ // Object settings
+ virtual void FlashEntity( int entityID );
+
+ // rules that define if you can see a player on the overview or not
+ virtual bool CanPlayerBeSeen(MapPlayer_t *player);
+
+ virtual int GetIconNumberFromTeamNumber( int teamNumber );
+
+protected:
+
+ virtual void DrawCamera();
+ virtual void DrawMapTexture();
+ virtual void DrawMapPlayers();
+ void DrawHostages();
+ void DrawBomb();
+ void DrawGoalIcons();
+ virtual void ResetRound();
+ virtual void InitTeamColorsAndIcons();
+ virtual void UpdateSizeAndPosition();
+ void UpdateGoalIcons();
+ void ClearGoalIcons();
+ virtual bool IsRadarLocked();
+ Vector2D PanelToMap( const Vector2D &panelPos );
+
+ bool AdjustPointToPanel(Vector2D *pos);
+ MapPlayer_t* GetPlayerByEntityID( int entityID );
+ MapPlayer_t* GetHostageByEntityID( int entityID );
+ virtual void UpdatePlayers();
+ void UpdateHostages();///< Update hostages in the MapPlayer list
+ void UpdateBomb();
+ void UpdateFlashes();
+ bool CreateRadarImage(const char *mapName, const char *radarFileName);
+ virtual bool RunHudAnimations(){ return false; }
+
+private:
+ bool DrawIconCS( int textureID,
+ int offscreenTextureID,
+ Vector pos,
+ float scale,
+ float angle,
+ int alpha,
+ bool allowRotation = true,
+ const char *text = NULL,
+ Color *textColor = NULL,
+ float status = -1,
+ Color *statusColor = NULL
+ );
+
+ int GetMasterAlpha( void );// The main alpha that the map part should be, determined by using the mode to look at the right convar
+ int GetBorderSize( void );// How far in from the edge of the panel we draw, based on mode. Let's the background fancy corners show.
+ CSMapPlayer_t* GetCSInfoForPlayerIndex( int index );
+ CSMapPlayer_t* GetCSInfoForPlayer(MapPlayer_t *player);
+ CSMapPlayer_t* GetCSInfoForHostage(MapPlayer_t *hostage);
+ bool CanHostageBeSeen(MapPlayer_t *hostage);
+
+ CSMapPlayer_t m_PlayersCSInfo[MAX_PLAYERS];
+ CSMapBomb_t m_bomb;
+ MapPlayer_t m_Hostages[MAX_HOSTAGES];
+ CSMapPlayer_t m_HostagesCSInfo[MAX_HOSTAGES];
+
+ CUtlVector< CSMapGoal_t > m_goalIcons;
+ bool m_goalIconsLoaded;
+
+ int m_TeamIconsSelf[MAP_ICON_COUNT];
+ int m_TeamIconsDead[MAP_ICON_COUNT];
+ int m_TeamIconsOffscreen[MAP_ICON_COUNT];
+ int m_TeamIconsDeadOffscreen[MAP_ICON_COUNT];
+
+ int m_bombIconPlanted;
+ int m_bombIconDropped;
+ int m_bombIconCarried;
+ int m_bombRingPlanted;
+ int m_bombRingDropped;
+ int m_bombRingCarried;
+ int m_bombRingCarriedOffscreen;
+ int m_radioFlash;
+ int m_radioFlashOffscreen;
+ int m_radarTint;
+ int m_hostageFollowing;
+ int m_hostageFollowingOffscreen;
+ int m_playerFacing;
+ int m_cameraIconFirst;
+ int m_cameraIconThird;
+ int m_cameraIconFree;
+ int m_hostageRescueIcon;
+ int m_bombSiteIconA;
+ int m_bombSiteIconB;
+
+ int m_nRadarMapTextureID; // texture id for radar version of current overview image
+
+ int m_playerPreferredMode; // The mode the player wants to be in for when we aren't being the radar
+};
+
+#endif // CSSPECTATORGUI_H
diff --git a/game/client/cstrike/VGUI/cstriketeammenu.cpp b/game/client/cstrike/VGUI/cstriketeammenu.cpp
new file mode 100644
index 0000000..4b39088
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstriketeammenu.cpp
@@ -0,0 +1,201 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstriketeammenu.h"
+#include "backgroundpanel.h"
+#include <convar.h>
+#include "hud.h" // for gEngfuncs
+#include "c_cs_player.h"
+#include "cs_gamerules.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSTeamMenu::CCSTeamMenu(IViewPort *pViewPort) : CTeamMenu(pViewPort)
+{
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCSTeamMenu::~CCSTeamMenu()
+{
+}
+
+void CCSTeamMenu::ShowPanel(bool bShow)
+{
+ if ( bShow )
+ {
+ engine->CheckPoint( "TeamMenu" );
+ }
+
+ BaseClass::ShowPanel( bShow );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called to update the menu with new information
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::Update( void )
+{
+ BaseClass::Update();
+
+ const ConVar *allowspecs = cvar->FindVar( "mp_allowspectators" );
+
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( !pPlayer || !CSGameRules() )
+ return;
+
+ if ( allowspecs && allowspecs->GetBool() )
+ {
+ // if we're not already a CT or T...or the freeze time isn't over yet...or we're dead
+ if ( pPlayer->GetTeamNumber() == TEAM_UNASSIGNED ||
+ CSGameRules()->IsFreezePeriod() ||
+ ( pPlayer && pPlayer->IsPlayerDead() ) )
+ {
+ SetVisibleButton("specbutton", true);
+ }
+ else
+ {
+ SetVisibleButton("specbutton", false);
+ }
+ }
+ else
+ {
+ SetVisibleButton("specbutton", false );
+ }
+
+ m_bVIPMap = false;
+
+ char mapName[MAX_MAP_NAME];
+
+ Q_FileBase( engine->GetLevelName(), mapName, sizeof(mapName) );
+
+ if ( !Q_strncmp( mapName, "maps/as_", 8 ) )
+ {
+ m_bVIPMap = true;
+ }
+
+ // if this isn't a VIP map or we're a spectator/terrorist, then disable the VIP button
+ if ( !CSGameRules()->IsVIPMap() || ( pPlayer->GetTeamNumber() != TEAM_CT ) )
+ {
+ SetVisibleButton("vipbutton", false);
+ }
+ else // this must be a VIP map and we must already be a CT
+ {
+ SetVisibleButton("vipbutton", true);
+ }
+
+ if( pPlayer->GetTeamNumber() == TEAM_UNASSIGNED ) // we aren't on a team yet
+ {
+ SetVisibleButton("CancelButton", false);
+ }
+ else
+ {
+ SetVisibleButton("CancelButton", true);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if ( state )
+ {
+ Button *pAutoButton = dynamic_cast< Button* >( FindChildByName( "autobutton" ) );
+ if ( pAutoButton )
+ {
+ pAutoButton->RequestFocus();
+ pAutoButton->SetArmed( true );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: When a team button is pressed it triggers this function to
+// cause the player to join a team
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::OnCommand( const char *command )
+{
+ if ( Q_stricmp( command, "vguicancel" ) )
+ {
+ engine->ClientCmd( command );
+ }
+
+
+ BaseClass::OnCommand(command);
+
+ gViewPortInterface->ShowBackGround( false );
+ OnClose();
+}
+
+
+void CCSTeamMenu::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_ENTER )
+ {
+ Button *pAutoButton = dynamic_cast< Button* >( FindChildByName( "autobutton" ) );
+ if ( pAutoButton )
+ {
+ pAutoButton->DoClick();
+ }
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the visibility of a button by name
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::SetVisibleButton(const char *textEntryName, bool state)
+{
+ Button *entry = dynamic_cast<Button *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetVisible(state);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTeamMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
diff --git a/game/client/cstrike/VGUI/cstriketeammenu.h b/game/client/cstrike/VGUI/cstriketeammenu.h
new file mode 100644
index 0000000..7b2ab0e
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstriketeammenu.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSTEAMMENU_H
+#define CSTEAMMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <teammenu.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays the team menu
+//-----------------------------------------------------------------------------
+class CCSTeamMenu : public CTeamMenu
+{
+private:
+ DECLARE_CLASS_SIMPLE( CCSTeamMenu, CTeamMenu );
+
+public:
+ CCSTeamMenu(IViewPort *pViewPort);
+ ~CCSTeamMenu();
+
+ void Update();
+ void ShowPanel( bool bShow );
+ virtual void SetVisible(bool state);
+
+private:
+ enum { NUM_TEAMS = 3 };
+
+ // VGUI2 override
+ virtual void OnCommand( const char *command);
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ // helper functions
+ void SetVisibleButton(const char *textEntryName, bool state);
+
+ bool m_bVIPMap;
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+#endif // CSTEAMMENU_H
diff --git a/game/client/cstrike/VGUI/cstriketextwindow.cpp b/game/client/cstrike/VGUI/cstriketextwindow.cpp
new file mode 100644
index 0000000..feedd23
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstriketextwindow.cpp
@@ -0,0 +1,146 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstriketextwindow.h"
+#include "backgroundpanel.h"
+#include <cdll_client_int.h>
+
+#include <vgui/IScheme.h>
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <filesystem.h>
+#include <KeyValues.h>
+#include <convar.h>
+#include <vgui_controls/ImageList.h>
+
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/BuildGroup.h>
+
+#include "IGameUIFuncs.h" // for key bindings
+#include <igameresources.h>
+extern IGameUIFuncs *gameuifuncs; // for key binding details
+
+#include <game/client/iviewport.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSTextWindow::CCSTextWindow(IViewPort *pViewPort) : CTextWindow( pViewPort )
+{
+ SetProportional( true );
+
+ m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
+
+ CreateBackground( this );
+ m_backgroundLayoutFinished = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCSTextWindow::~CCSTextWindow()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTextWindow::Update()
+{
+ BaseClass::Update();
+
+ m_pOK->RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTextWindow::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if ( state )
+ {
+ m_pOK->RequestFocus();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: shows the text window
+//-----------------------------------------------------------------------------
+void CCSTextWindow::ShowPanel(bool bShow)
+{
+ if ( bShow )
+ {
+ // get key binding if shown
+ if ( m_iScoreBoardKey == BUTTON_CODE_INVALID ) // you need to lookup the jump key AFTER the engine has loaded
+ {
+ m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" );
+ }
+ }
+
+ BaseClass::ShowPanel( bShow );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTextWindow::OnKeyCodePressed( KeyCode code )
+{
+ //We manually intercept the ENTER key so in case the button loses focus
+ //ENTER still moves you through the MOTD screen.
+ if ( code == KEY_ENTER || code == KEY_XBUTTON_A || code == KEY_XBUTTON_B )
+ {
+ m_pOK->DoClick();
+ }
+ else if ( m_iScoreBoardKey != BUTTON_CODE_INVALID && m_iScoreBoardKey == code )
+ {
+ gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, true );
+ gViewPortInterface->PostMessageToPanel( PANEL_SCOREBOARD, new KeyValues( "PollHideCode", "code", code ) );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The CS background is painted by image panels, so we should do nothing
+//-----------------------------------------------------------------------------
+void CCSTextWindow::PaintBackground()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scale / center the window
+//-----------------------------------------------------------------------------
+void CCSTextWindow::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // stretch the window to fullscreen
+ if ( !m_backgroundLayoutFinished )
+ LayoutBackgroundPanel( this );
+ m_backgroundLayoutFinished = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSTextWindow::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ ApplyBackgroundSchemeSettings( this, pScheme );
+}
+
diff --git a/game/client/cstrike/VGUI/cstriketextwindow.h b/game/client/cstrike/VGUI/cstriketextwindow.h
new file mode 100644
index 0000000..bd7c707
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstriketextwindow.h
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSTEXTWINDOW_H
+#define CSTEXTWINDOW_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vguitextwindow.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: displays the MOTD
+//-----------------------------------------------------------------------------
+
+class CCSTextWindow : public CTextWindow
+{
+private:
+ DECLARE_CLASS_SIMPLE( CCSTextWindow, CTextWindow );
+
+public:
+ CCSTextWindow(IViewPort *pViewPort);
+ virtual ~CCSTextWindow();
+
+ virtual void Update();
+ virtual void SetVisible(bool state);
+ virtual void ShowPanel( bool bShow );
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+
+protected:
+ ButtonCode_t m_iScoreBoardKey;
+
+ // Background panel -------------------------------------------------------
+
+public:
+ virtual void PaintBackground();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ bool m_backgroundLayoutFinished;
+
+ // End background panel ---------------------------------------------------
+};
+
+
+#endif // CSTEXTWINDOW_H
diff --git a/game/client/cstrike/VGUI/lifetime_stats_page.cpp b/game/client/cstrike/VGUI/lifetime_stats_page.cpp
new file mode 100644
index 0000000..89c0129
--- /dev/null
+++ b/game/client/cstrike/VGUI/lifetime_stats_page.cpp
@@ -0,0 +1,257 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "lifetime_stats_page.h"
+#include <vgui_controls/SectionedListPanel.h>
+#include "cs_client_gamestats.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CLifetimeStatsPage::CLifetimeStatsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSLifetimeStatsDialog")
+{
+ m_allStatsGroupPanel = AddGroup( L"all", "Stats_Button_All", L"All" );
+ m_detailedWeaponStatsGroupPanel = AddGroup( L"weapon", "Stats_Button_Weapon", L"Weapon Stats" );
+ m_specialSkillsStatsGroupPanel = AddGroup( L"skills", "Stats_Button_Skills", L"Special Skills" );
+ m_mapAndMiscellanyStatsGroupPanel = AddGroup( L"map", "Stats_Button_Misc", L"Miscellaneous" );
+ m_mapVictoryStatsGroupPanel = AddGroup( L"map", "Stats_Button_Victories", L"Map Victories" );
+ m_missionAndObjectiveStatsGroupPanel = AddGroup( L"mission", "Stats_Button_Mission", L"Mission && Objectives" );
+
+ m_allStatsGroupPanel->SetGroupActive(true);
+}
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from statsdialog.res in hl2/resource/ui/
+//-----------------------------------------------------------------------------
+void CLifetimeStatsPage::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings("resource/ui/CSLifetimeStatsDialog.res");
+
+ m_statsList->AddColumnToSection( 0, "name", "", SectionedListPanel::COLUMN_CENTER, 280);
+ m_statsList->AddColumnToSection( 0, "playerValue", "", SectionedListPanel::COLUMN_CENTER, 250);
+}
+
+void CLifetimeStatsPage::RepopulateStats()
+{
+ m_statsList->RemoveAll();
+
+ const StatsCollection_t& personalLifetimeStats = g_CSClientGameStats.GetLifetimeStats();
+
+ if (m_missionAndObjectiveStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_ROUNDS_WON, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_DEATHS, personalLifetimeStats);
+ AddKillToDeathStat(personalLifetimeStats);
+ AddSimpleStat(CSSTAT_DAMAGE, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_NUM_BOMBS_PLANTED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_NUM_BOMBS_DEFUSED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_NUM_HOSTAGES_RESCUED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_PISTOLROUNDS_WON, personalLifetimeStats);
+ }
+
+ if (m_specialSkillsStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_MVPS, personalLifetimeStats);
+ AddFavoriteWeaponStat(personalLifetimeStats);
+ AddSimpleStat(CSSTAT_SHOTS_FIRED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_SHOTS_HIT, personalLifetimeStats);
+ AddAccuracyStat(personalLifetimeStats);
+ AddSimpleStat(CSSTAT_DOMINATIONS, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_DOMINATION_OVERKILLS, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_REVENGES, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS_HEADSHOT, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS_ENEMY_BLINDED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS_ENEMY_WEAPON, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_KILLS_KNIFE_FIGHT, personalLifetimeStats);
+ }
+
+ if (m_mapAndMiscellanyStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_MONEY_EARNED, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_DECAL_SPRAYS, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_NIGHTVISION_DAMAGE, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_NUM_BROKEN_WINDOWS, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_WEAPONS_DONATED, personalLifetimeStats);
+ }
+
+ if (m_mapVictoryStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_ASSAULT, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_COMPOUND, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_HAVANA, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_ITALY, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_MILITIA, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_CS_OFFICE, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_AZTEC, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_CBBLE, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_CHATEAU, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_DUST2, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_DUST, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_INFERNO, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_NUKE, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_PIRANESI, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_PORT, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_PRODIGY, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_TIDES, personalLifetimeStats);
+ AddSimpleStat(CSSTAT_MAP_WINS_DE_TRAIN, personalLifetimeStats);
+ }
+
+
+ if (m_detailedWeaponStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ CSStatType_t hitsStat = CSSTAT_HITS_DEAGLE;
+ CSStatType_t shotsStat = CSSTAT_SHOTS_DEAGLE;
+ for (CSStatType_t killStat = CSSTAT_KILLS_DEAGLE ; killStat <= CSSTAT_KILLS_HEGRENADE ; killStat = (CSStatType_t)(killStat + 1))
+ {
+ if (shotsStat <= CSSTAT_SHOTS_M249)
+ {
+ AddSimpleStat(shotsStat, personalLifetimeStats);
+ }
+ if (hitsStat <= CSSTAT_HITS_M249)
+ {
+ AddSimpleStat(hitsStat, personalLifetimeStats);
+ }
+ AddSimpleStat(killStat, personalLifetimeStats);
+
+ hitsStat = (CSStatType_t)(hitsStat + 1);
+ shotsStat = (CSStatType_t)(shotsStat + 1);
+ }
+ }
+
+ int itemCount = m_statsList->GetItemCount();
+ for (int i = 0; i < itemCount ; ++i)
+ {
+ m_statsList->SetItemBgColor(i, Color(0,0,0,0));
+ }
+}
+
+int CLifetimeStatsPage::AddSimpleStat( int desiredStat, const StatsCollection_t& personalLifetimeStats)
+{
+ PlayerStatData_t stat = g_CSClientGameStats.GetStatById(desiredStat);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", stat.pStatDisplayName );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ char buf[64];
+ Q_snprintf( buf, sizeof( buf ), "%d", personalLifetimeStats[stat.iStatId] );
+ pKeyValues->SetString( "playerValue", (personalLifetimeStats[stat.iStatId])?buf:"" );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+int CLifetimeStatsPage::AddFavoriteWeaponStat(const StatsCollection_t& personalLifetimeStats)
+{
+ PlayerStatData_t statPlayerBestWeapon;
+ statPlayerBestWeapon.iStatId = CSSTAT_UNDEFINED;
+
+ int previousBestKills = 0;
+
+ for (CSStatType_t statId = CSSTAT_KILLS_DEAGLE ; statId <= CSSTAT_KILLS_M249; statId = (CSStatType_t)(statId + 1))
+ {
+ PlayerStatData_t stat = g_CSClientGameStats.GetStatById( statId );
+
+ //Compare this to previous Weapons
+ int playerKillsWithWeapon = personalLifetimeStats[statId];
+ {
+ if (playerKillsWithWeapon > previousBestKills)
+ {
+ statPlayerBestWeapon = stat;
+ previousBestKills = playerKillsWithWeapon;
+ }
+ }
+ }
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", LocalizeTagOrUseDefault( "Stats_FavoriteWeapon", L"Favorite Weapon" ) );
+
+ pKeyValues->SetWString( "playerValue", TranslateWeaponKillIDToAlias(statPlayerBestWeapon.iStatId) );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+
+int CLifetimeStatsPage::AddKillToDeathStat(const StatsCollection_t& personalLifetimeStats)
+{
+ PlayerStatData_t statKills = g_CSClientGameStats.GetStatById(CSSTAT_KILLS);
+ PlayerStatData_t statDeaths = g_CSClientGameStats.GetStatById(CSSTAT_DEATHS);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", LocalizeTagOrUseDefault( "Stats_KillToDeathRatio", L"Kill to Death Ratio" ) );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ float playerKills = personalLifetimeStats[statKills.iStatId];
+ float playerDeaths = personalLifetimeStats[statDeaths.iStatId];
+ float playerKillToDeathRatio = 1.0f;
+
+ if (playerDeaths > 0)
+ {
+ playerKillToDeathRatio = playerKills / playerDeaths;
+ }
+
+ char buf[64];
+ Q_snprintf( buf, sizeof( buf ), "%.2f", playerKillToDeathRatio );
+ pKeyValues->SetString( "playerValue", (playerKillToDeathRatio)?buf:"" );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+int CLifetimeStatsPage::AddAccuracyStat(const StatsCollection_t& personalLifetimeStats)
+{
+ PlayerStatData_t statHits = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_HIT);
+ PlayerStatData_t statShots = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_FIRED);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", LocalizeTagOrUseDefault( "Stats_Accuracy", L"Accuracy" ) );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ float playerHits = personalLifetimeStats[statHits.iStatId];
+ float playerShots = personalLifetimeStats[statShots.iStatId];
+ float playerAccuracy = 0.0;
+
+ if (playerShots > 0)
+ {
+ playerAccuracy = 100.0f * playerHits / playerShots;
+ }
+
+ char buf[64];
+ Q_snprintf( buf, sizeof( buf ), "%.1f%%", playerAccuracy );
+ pKeyValues->SetString( "playerValue", (playerAccuracy)?buf:"" );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
diff --git a/game/client/cstrike/VGUI/lifetime_stats_page.h b/game/client/cstrike/VGUI/lifetime_stats_page.h
new file mode 100644
index 0000000..8a2af6b
--- /dev/null
+++ b/game/client/cstrike/VGUI/lifetime_stats_page.h
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSLifetimeSTATSPAGE_H
+#define CSLifetimeSTATSPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "base_stats_page.h"
+
+class CLifetimeStatsPage : public CBaseStatsPage
+{
+ DECLARE_CLASS_SIMPLE ( CLifetimeStatsPage, CBaseStatsPage );
+
+public:
+ CLifetimeStatsPage( vgui::Panel *parent, const char *name );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ void RepopulateStats();
+ int AddSimpleStat( int desiredStat, const StatsCollection_t& personalLifetimeStats);
+ int AddAccuracyStat(const StatsCollection_t& personalLifetimeStats);
+ int AddFavoriteWeaponStat(const StatsCollection_t& personalLifetimeStats);
+ int AddKillToDeathStat(const StatsCollection_t& personalLifetimeStats);
+
+ CBaseStatGroupPanel* m_allStatsGroupPanel;
+ CBaseStatGroupPanel* m_detailedWeaponStatsGroupPanel;
+ CBaseStatGroupPanel* m_specialSkillsStatsGroupPanel;
+ CBaseStatGroupPanel* m_mapAndMiscellanyStatsGroupPanel;
+ CBaseStatGroupPanel* m_mapVictoryStatsGroupPanel;
+ CBaseStatGroupPanel* m_missionAndObjectiveStatsGroupPanel;
+
+
+};
+
+#endif // CSLifetimeSTATSPAGE_H
diff --git a/game/client/cstrike/VGUI/match_stats_page.cpp b/game/client/cstrike/VGUI/match_stats_page.cpp
new file mode 100644
index 0000000..9130176
--- /dev/null
+++ b/game/client/cstrike/VGUI/match_stats_page.cpp
@@ -0,0 +1,334 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "match_stats_page.h"
+#include <vgui_controls/SectionedListPanel.h>
+#include "c_team.h"
+#include "cs_client_gamestats.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CMatchStatsPage::CMatchStatsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSMatchStatsDialog")
+{
+ m_allStatsGroupPanel = AddGroup( L"all", "Stats_Button_All", L"All" );
+ m_detailedWeaponStatsGroupPanel = AddGroup( L"weapon", "Stats_Button_Weapon", L"Weapon Stats" );
+ m_specialSkillsStatsGroupPanel = AddGroup( L"skills", "Stats_Button_Skills", L"Special Skills" );
+ m_mapAndMiscellanyStatsGroupPanel = AddGroup( L"map", "Stats_Button_Misc", L"Miscellaneous" );
+ m_missionAndObjectiveStatsGroupPanel = AddGroup( L"mission", "Stats_Button_Mission", L"Mission && Objectives" );
+
+ m_allStatsGroupPanel->SetGroupActive(true);
+
+ m_ResetNotice = new Label( this, "ResetNotice", "");
+}
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from statsdialog.res in hl2/resource/ui/
+//-----------------------------------------------------------------------------
+void CMatchStatsPage::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings("resource/ui/CSMatchStatsDialog.res");
+ m_statsList->AddColumnToSection( 0, "name", "", SectionedListPanel::COLUMN_CENTER, 180);
+ m_statsList->AddColumnToSection( 0, "playerValue", "", SectionedListPanel::COLUMN_CENTER, 100);
+ m_statsList->AddColumnToSection( 0, "ctValue", "", SectionedListPanel::COLUMN_CENTER, 100);
+ m_statsList->AddColumnToSection( 0, "tValue", " ", SectionedListPanel::COLUMN_CENTER, 100);
+ m_statsList->AddColumnToSection( 0, "serverValue", "", SectionedListPanel::COLUMN_CENTER, 100);
+}
+
+void CMatchStatsPage::RepopulateStats()
+{
+ m_statsList->RemoveAll();
+
+ RoundStatsDirectAverage_t* tStats = g_CSClientGameStats.GetDirectTStatsAverages();
+ RoundStatsDirectAverage_t* ctStats = g_CSClientGameStats.GetDirectCTStatsAverages();
+ RoundStatsDirectAverage_t* serverStats = g_CSClientGameStats.GetDirectPlayerStatsAverages();
+ const StatsCollection_t& personalMatchStats = g_CSClientGameStats.GetMatchStats();
+
+ if (m_missionAndObjectiveStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_ROUNDS_WON, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_DEATHS, personalMatchStats, tStats, ctStats, serverStats);
+ AddKillToDeathStat(personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_DAMAGE, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_NUM_BOMBS_PLANTED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_NUM_BOMBS_DEFUSED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_NUM_HOSTAGES_RESCUED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_PISTOLROUNDS_WON, personalMatchStats, tStats, ctStats, serverStats);
+ }
+
+ if (m_specialSkillsStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_MVPS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_SHOTS_FIRED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_SHOTS_HIT, personalMatchStats, tStats, ctStats, serverStats);
+ AddAccuracyStat(personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_DOMINATIONS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_DOMINATION_OVERKILLS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_REVENGES, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS_HEADSHOT, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS_ENEMY_BLINDED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS_ENEMY_WEAPON, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_KILLS_KNIFE_FIGHT, personalMatchStats, tStats, ctStats, serverStats);
+ }
+
+ if (m_mapAndMiscellanyStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ AddSimpleStat(CSSTAT_MONEY_EARNED, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_DECAL_SPRAYS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_NIGHTVISION_DAMAGE, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_NUM_BROKEN_WINDOWS, personalMatchStats, tStats, ctStats, serverStats);
+ AddSimpleStat(CSSTAT_WEAPONS_DONATED, personalMatchStats, tStats, ctStats, serverStats);
+ }
+
+ if (m_detailedWeaponStatsGroupPanel->IsGroupActive() || m_allStatsGroupPanel->IsGroupActive())
+ {
+ CSStatType_t hitsStat = CSSTAT_HITS_DEAGLE;
+ CSStatType_t shotsStat = CSSTAT_SHOTS_DEAGLE;
+ for (CSStatType_t killStat = CSSTAT_KILLS_DEAGLE ; killStat <= CSSTAT_KILLS_HEGRENADE ; killStat = (CSStatType_t)(killStat + 1))
+ {
+ if (shotsStat <= CSSTAT_SHOTS_M249)
+ {
+ AddSimpleStat(shotsStat, personalMatchStats, tStats, ctStats, serverStats);
+ }
+
+ if (hitsStat <= CSSTAT_HITS_M249)
+ {
+ AddSimpleStat(hitsStat, personalMatchStats, tStats, ctStats, serverStats);
+ }
+ AddSimpleStat(killStat, personalMatchStats, tStats, ctStats, serverStats);
+
+ hitsStat = (CSStatType_t)(hitsStat + 1);
+ shotsStat = (CSStatType_t)(shotsStat + 1);
+ }
+ }
+
+ int itemCount = m_statsList->GetItemCount();
+ for (int i = 0; i < itemCount ; ++i)
+ {
+ m_statsList->SetItemBgColor(i, Color(0,0,0,0));
+ }
+}
+
+int CMatchStatsPage::AddSimpleStat( int desiredStat, const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats )
+{
+ PlayerStatData_t stat = g_CSClientGameStats.GetStatById(desiredStat);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", stat.pStatDisplayName );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ char buf[64];
+ Q_snprintf( buf, sizeof( buf ), "%d", personalMatchStats[stat.iStatId] );
+ pKeyValues->SetString( "playerValue", (personalMatchStats[stat.iStatId])?buf:"" );
+
+ if (desiredStat == CSSTAT_ROUNDS_WON)
+ {
+ C_Team *ts = GetGlobalTeam(TEAM_TERRORIST);
+ if (ts)
+ {
+ Q_snprintf( buf, sizeof( buf ), "%d", ts->Get_Score() );
+ pKeyValues->SetString( "tValue", buf );
+ }
+
+ C_Team *cts = GetGlobalTeam(TEAM_CT);
+ if (cts){
+ Q_snprintf( buf, sizeof( buf ), "%d", cts->Get_Score());
+ pKeyValues->SetString( "ctValue", buf );
+ }
+ }
+ else
+ {
+ Q_snprintf( buf, sizeof( buf ), "%.1f", tStats->m_fStat[stat.iStatId] );
+ pKeyValues->SetString( "tValue", (tStats->m_fStat[stat.iStatId]||personalMatchStats[stat.iStatId])?buf:"" );
+
+ Q_snprintf( buf, sizeof( buf ), "%.1f", ctStats->m_fStat[stat.iStatId] );
+ pKeyValues->SetString( "ctValue", (ctStats->m_fStat[stat.iStatId]||personalMatchStats[stat.iStatId])?buf:"" );
+ }
+
+ Q_snprintf( buf, sizeof( buf ), "%.1f", serverStats->m_fStat[stat.iStatId] );
+ pKeyValues->SetString( "serverValue", (serverStats->m_fStat[stat.iStatId]||personalMatchStats[stat.iStatId])?buf:"" );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+
+int CMatchStatsPage::AddKillToDeathStat(const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats )
+{
+ PlayerStatData_t statKills = g_CSClientGameStats.GetStatById(CSSTAT_KILLS);
+ PlayerStatData_t statDeaths = g_CSClientGameStats.GetStatById(CSSTAT_DEATHS);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+
+ pKeyValues->SetWString( "name", LocalizeTagOrUseDefault( "Stats_KillToDeathRatio", L"Kill to Death Ratio" ) );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ float playerKills = personalMatchStats[statKills.iStatId];
+ float tKills = tStats->m_fStat[statKills.iStatId];
+ float ctKills = ctStats->m_fStat[statKills.iStatId];
+ float serverKills = serverStats->m_fStat[statKills.iStatId];
+
+ float playerDeaths = personalMatchStats[statDeaths.iStatId];
+ float tDeaths = tStats->m_fStat[statDeaths.iStatId];
+ float ctDeaths = ctStats->m_fStat[statDeaths.iStatId];
+ float serverDeaths = serverStats->m_fStat[statDeaths.iStatId];
+
+ char buf[64];
+
+ if (playerDeaths > 0)
+ {
+ float playerKillToDeathRatio = playerKills / playerDeaths;
+ Q_snprintf( buf, sizeof( buf ), "%.2f", playerKillToDeathRatio );
+ pKeyValues->SetString( "playerValue", (playerKillToDeathRatio)?buf:"" );
+ }
+ else
+ {
+ pKeyValues->SetString( "playerValue", "" );
+ }
+
+
+ if (tDeaths > 0)
+ {
+ float tKillToDeathRatio = tKills / tDeaths;
+ Q_snprintf( buf, sizeof( buf ), "%.2f", tKillToDeathRatio );
+ pKeyValues->SetString( "tValue", ((playerKills&&playerDeaths)||tKillToDeathRatio)?buf:"" );
+
+ }
+ else
+ {
+ pKeyValues->SetString( "tValue", "" );
+ }
+
+ if (ctDeaths > 0)
+ {
+ float ctKillToDeathRatio = ctKills / ctDeaths;
+ Q_snprintf( buf, sizeof( buf ), "%.2f", ctKillToDeathRatio);
+ pKeyValues->SetString( "ctValue", ((playerKills&&playerDeaths)||ctKillToDeathRatio)?buf:"" );
+ }
+ else
+ {
+ pKeyValues->SetString( "ctValue", "" );
+ }
+
+ if (serverDeaths > 0)
+ {
+ float serverKillToDeathRatio = serverKills / serverDeaths;
+ Q_snprintf( buf, sizeof( buf ), "%.2f", serverKillToDeathRatio );
+ pKeyValues->SetString( "serverValue", ((playerKills&&playerDeaths)||serverKillToDeathRatio)?buf:"" );
+ }
+ else
+ {
+ pKeyValues->SetString( "serverValue", "" );
+ }
+
+
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+
+
+int CMatchStatsPage::AddAccuracyStat(const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats )
+{
+ PlayerStatData_t statHits = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_HIT);
+ PlayerStatData_t statShots = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_FIRED);
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ pKeyValues->SetWString( "name", LocalizeTagOrUseDefault( "Stats_Accuracy", L"Accuracy" ) );
+ pKeyValues->SetFloat( "playerValue", 0 );
+
+ float playerHits = personalMatchStats[statHits.iStatId];
+ float tHits = tStats->m_fStat[statHits.iStatId];
+ float ctHits = ctStats->m_fStat[statHits.iStatId];
+ float serverHits = serverStats->m_fStat[statHits.iStatId];
+
+ float playerShots = personalMatchStats[statShots.iStatId];
+ float tShots = tStats->m_fStat[statShots.iStatId];
+ float ctShots = ctStats->m_fStat[statShots.iStatId];
+ float serverShots = serverStats->m_fStat[statShots.iStatId];
+
+ float playerAccuracy = 0.0;
+ float tAccuracy = 0.0;
+ float ctAccuracy = 0.0;
+ float serverAccuracy = 0.0;
+
+ if (playerShots > 0)
+ {
+ playerAccuracy = 100.0f * playerHits / playerShots;
+ }
+
+ if (tShots > 0)
+ {
+ tAccuracy = 100.0f * tHits / tShots;
+ }
+
+ if (ctShots > 0)
+ {
+ ctAccuracy = 100.0f * ctHits / ctShots;
+ }
+
+ if (serverShots > 0)
+ {
+ serverAccuracy = 100.0f * serverHits / serverShots;
+ }
+
+ char buf[64];
+ Q_snprintf( buf, sizeof( buf ), "%.1f%%", playerAccuracy );
+ pKeyValues->SetString( "playerValue", (playerAccuracy)?buf:"" );
+
+ Q_snprintf( buf, sizeof( buf ), "%.1f%%", tAccuracy);
+ pKeyValues->SetString( "tValue", (playerAccuracy||tAccuracy)?buf:"" );
+
+ Q_snprintf( buf, sizeof( buf ), "%.1f%%", ctAccuracy );
+ pKeyValues->SetString( "ctValue", (playerAccuracy||ctAccuracy)?buf:"" );
+
+ Q_snprintf( buf, sizeof( buf ), "%.1f%%", serverAccuracy );
+ pKeyValues->SetString( "serverValue", (playerAccuracy||serverAccuracy)?buf:"" );
+
+ int newItem = m_statsList->AddItem(0, pKeyValues);
+ pKeyValues->deleteThis();
+
+ m_statsList->SetItemFont(newItem , m_listItemFont);
+ m_statsList->SetItemFgColor(newItem, Color(197,197,197,255));
+
+ return newItem;
+}
+
+
+void CMatchStatsPage::OnSizeChanged(int newWide, int newTall)
+{
+ BaseClass::OnSizeChanged(newWide, newTall);
+
+ if (m_statsList)
+ {
+ if (m_ResetNotice)
+ {
+ int labelX, labelY, listX, listY, listWide, listTall;
+ m_statsList->GetBounds(listX, listY, listWide, listTall);
+
+ m_ResetNotice->GetPos(labelX, labelY);
+ m_ResetNotice->SetPos(labelX, listY + listTall + 4);
+ }
+ }
+}
diff --git a/game/client/cstrike/VGUI/match_stats_page.h b/game/client/cstrike/VGUI/match_stats_page.h
new file mode 100644
index 0000000..9c85902
--- /dev/null
+++ b/game/client/cstrike/VGUI/match_stats_page.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSMATCHSTATSPAGE_H
+#define CSMATCHSTATSPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "base_stats_page.h"
+
+class CMatchStatsPage : public CBaseStatsPage
+{
+ DECLARE_CLASS_SIMPLE ( CMatchStatsPage, CBaseStatsPage );
+
+public:
+ CMatchStatsPage( vgui::Panel *parent, const char *name );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ void RepopulateStats();
+ int AddSimpleStat( int desiredStat, const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats );
+ int AddAccuracyStat(const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats );
+ int AddKillToDeathStat(const StatsCollection_t& personalMatchStats, RoundStatsDirectAverage_t* tStats, RoundStatsDirectAverage_t* ctStats, RoundStatsDirectAverage_t* serverStats );
+ virtual void OnSizeChanged(int wide, int tall);
+
+ CBaseStatGroupPanel* m_allStatsGroupPanel;
+ CBaseStatGroupPanel* m_detailedWeaponStatsGroupPanel;
+ CBaseStatGroupPanel* m_specialSkillsStatsGroupPanel;
+ CBaseStatGroupPanel* m_mapAndMiscellanyStatsGroupPanel;
+ CBaseStatGroupPanel* m_missionAndObjectiveStatsGroupPanel;
+
+ vgui::Label* m_ResetNotice;
+};
+
+#endif // CSMATCHSTATSPAGE_H
diff --git a/game/client/cstrike/VGUI/stat_card.cpp b/game/client/cstrike/VGUI/stat_card.cpp
new file mode 100644
index 0000000..648b286
--- /dev/null
+++ b/game/client/cstrike/VGUI/stat_card.cpp
@@ -0,0 +1,106 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Create and display a win panel at the end of a round displaying interesting stats and info about the round.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "stat_card.h"
+#include "vgui_controls/AnimationController.h"
+#include "iclientmode.h"
+#include "c_playerresource.h"
+#include <vgui_controls/Label.h>
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include "fmtstr.h"
+#include "../../public/steam/steam_api.h"
+#include "c_cs_player.h"
+#include "cs_gamestats_shared.h"
+#include "cs_client_gamestats.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+StatCard::StatCard(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSStatCard")
+{
+ //m_pAvatarDefault = new ImagePanel(this, "");
+ //m_pBackgroundArt = new ImagePanel(this, "BackgroundArt");
+ m_pAvatar = new CAvatarImagePanel(this, "Avatar");
+ m_pAvatar->SetShouldScaleImage(true);
+ m_pAvatar->SetShouldDrawFriendIcon(false);
+ m_pAvatar->SetSize(64,64);
+
+ m_pName= new Label(this, "Name", "Name");
+ m_pKillToDeathRatio = new Label(this, "KillToDeath", "KillToDeath");
+ m_pStars = new Label(this, "Stars", "Stars");
+}
+
+StatCard::~StatCard()
+{
+
+}
+
+
+void StatCard::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings("Resource/UI/CSStatCard.res");
+
+ //m_pBackgroundArt->SetShouldScaleImage(true);
+ //m_pBackgroundArt->SetImage("../VGUI/achievements/achievement-btn-up");
+
+ SetBgColor(Color(0,0,0,0));
+
+ UpdateInfo();
+}
+
+void StatCard::UpdateInfo()
+{
+ const StatsCollection_t& personalLifetimeStats = g_CSClientGameStats.GetLifetimeStats();
+
+ int stars = personalLifetimeStats[CSSTAT_MVPS];
+ float kills = personalLifetimeStats[CSSTAT_KILLS];
+ float deaths = personalLifetimeStats[CSSTAT_DEATHS];
+ wchar_t buf[64], numBuf[64];
+
+ if (deaths > 0)
+ {
+ float killToDeath = kills / deaths;
+
+ _snwprintf( numBuf, ARRAYSIZE( numBuf ), L"%.2f", killToDeath);
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf),
+ g_pVGuiLocalize->Find( "#GameUI_Stats_LastMatch_KDRatio" ), 1, numBuf );
+ m_pKillToDeathRatio->SetText( buf );
+ }
+ else
+ {
+ m_pKillToDeathRatio->SetText("");
+ }
+
+ _snwprintf( numBuf, ARRAYSIZE( numBuf ), L"%i", stars);
+ g_pVGuiLocalize->ConstructString( buf, sizeof(buf),
+ g_pVGuiLocalize->Find( "#GameUI_Stats_LastMatch_MVPS" ), 1, numBuf );
+ m_pStars->SetText( buf );
+
+ if (steamapicontext)
+ {
+ ISteamFriends* friends = steamapicontext->SteamFriends();
+ if (friends)
+ {
+ m_pName->SetText(friends->GetPersonaName());
+ }
+ }
+
+ // Display the player avatar
+ if (m_pAvatar && steamapicontext && steamapicontext->SteamUser())
+ {
+ m_pAvatar->SetPlayer( steamapicontext->SteamUser()->GetSteamID(), k_EAvatarSize64x64 );
+ m_pAvatar->SetVisible( true );
+ }
+}
diff --git a/game/client/cstrike/VGUI/stat_card.h b/game/client/cstrike/VGUI/stat_card.h
new file mode 100644
index 0000000..5a393ab
--- /dev/null
+++ b/game/client/cstrike/VGUI/stat_card.h
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef STATCARD_H
+#define STATCARD_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/IScheme.h>
+#include "hud.h"
+#include "hudelement.h"
+#include "vgui_avatarimage.h"
+#include "cs_shareddefs.h"
+#include <vgui_controls/EditablePanel.h>
+
+using namespace vgui;
+
+class StatCard : public EditablePanel
+{
+private:
+ DECLARE_CLASS_SIMPLE( StatCard, EditablePanel );
+
+public:
+ StatCard(vgui::Panel *parent, const char *name);
+ ~StatCard();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ void UpdateInfo();
+
+protected:
+
+
+ ImagePanel* m_pAvatarDefault;
+ //ImagePanel* m_pBackgroundArt;
+ CAvatarImagePanel* m_pAvatar;
+
+ Label* m_pName;
+ Label* m_pKillToDeathRatio;
+ Label* m_pStars;
+
+
+private:
+};
+
+#endif //STATCARD_H \ No newline at end of file
diff --git a/game/client/cstrike/VGUI/stats_summary.cpp b/game/client/cstrike/VGUI/stats_summary.cpp
new file mode 100644
index 0000000..b2224c0
--- /dev/null
+++ b/game/client/cstrike/VGUI/stats_summary.cpp
@@ -0,0 +1,684 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Display a list of achievements for the current game
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "stats_summary.h"
+#include "vgui_controls/Button.h"
+#include "vgui/ILocalize.h"
+#include "ixboxsystem.h"
+#include "iachievementmgr.h"
+#include "filesystem.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/ImageList.h"
+#include "fmtstr.h"
+#include "c_cs_playerresource.h"
+
+#include "../../../public/steam/steam_api.h"
+#include "achievementmgr.h"
+#include "../../../../public/vgui/IScheme.h"
+#include "../vgui_controls/ScrollBar.h"
+#include "stat_card.h"
+
+#include "weapon_csbase.h"
+#include "cs_weapon_parse.h"
+#include "buy_presets/buy_presets.h"
+#include "win_panel_round.h"
+#include "cs_client_gamestats.h"
+#include "achievements_cs.h"
+#include "ienginevgui.h"
+
+
+#define STAT_NUM_ARRAY_LENGTH 8
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+#include <locale.h>
+
+extern CAchievementMgr g_AchievementMgrCS;
+
+const int maxRecentAchievementToDisplay = 10;
+
+/**
+ * public ConvertNumberToMantissaSuffixForm()
+ *
+ * Convert a floating point number to a string form incorporating a mantissa and a magnitude suffix (such as "K" for thousands).
+ *
+ * Parameters:
+ * fNum -
+ * textBuffer - output buffer
+ * textBufferLen - size of output buffer in characters
+ * bTrimTrailingZeros - indicates whether to remove trailing zeros of numbers without suffixes (e.g., "32.00000" becomes "32")
+ * iSignificantDigits - the desired number of significant digits in the result (e.g, "1.23" has 3 significant digits)
+ *
+ * Returns:
+ * bool - true on success
+ */
+bool ConvertNumberToMantissaSuffixForm(float fNum, wchar_t* textBuffer, int textBufferLen, bool bTrimTrailingZeros = true, int iSignificantDigits = 3)
+{
+ // we need room for at least iSignificantDigits + 3 characters
+ Assert(textBufferLen >= iSignificantDigits + 3);
+
+ // find the correct power of 1000 exponent
+ Assert(fNum >= 0.0f);
+ int iExponent = 0;
+ while (fNum >= powf(10.0f, iExponent + 3))
+ {
+ iExponent += 3;
+ }
+
+ // look in the localization table for the matching suffix; fallback to lower suffixes when necessary
+ wchar_t *pSuffix = NULL;
+ for (; iExponent > 0; iExponent -= 3)
+ {
+ char localizationToken[64];
+ V_snprintf(localizationToken, sizeof(localizationToken), "#GameUI_NumSuffix_E%i", iExponent);
+ pSuffix = g_pVGuiLocalize->Find(localizationToken);
+ if (pSuffix != NULL)
+ break;
+ }
+
+ V_snwprintf(textBuffer, textBufferLen, L"%f", fNum / powf(10.0f, iExponent));
+ textBuffer[textBufferLen - 1] = L'\0';
+
+ lconv* pLocaleSettings = localeconv();
+ wchar_t decimalWChar = *pLocaleSettings->decimal_point;
+ wchar_t* pDecimalPos = wcschr(textBuffer, decimalWChar);
+ if (pDecimalPos == NULL)
+ {
+ Msg("ConvertNumberToMantissaSuffixForm(): decimal point not found in string %S for value %f\n", textBuffer, fNum);
+ return false;
+ }
+
+ // trim trailing zeros
+ int iNumCharsInBuffer = wcslen(textBuffer);
+ if (pSuffix == NULL && bTrimTrailingZeros)
+ {
+ wchar_t* pLastChar;
+ for (pLastChar = &textBuffer[iNumCharsInBuffer - 1]; pLastChar > pDecimalPos; --pLastChar)
+ {
+ if (*pLastChar != L'0') // note that this is checking for '0', not a NULL terminator
+ break;
+
+ *pLastChar = L'\0';
+ }
+ if (pLastChar == pDecimalPos)
+ *pLastChar = L'\0';
+ }
+
+ // truncate the mantissa to the right of the decimal point so that it doesn't exceed the significant digits
+ if (pDecimalPos != NULL && iNumCharsInBuffer > iSignificantDigits + 1)
+ {
+ if (pDecimalPos - &textBuffer[0] < iSignificantDigits)
+ textBuffer[iSignificantDigits + 1] = L'\0'; // truncate at the correct number of significant digits
+ else
+ *pDecimalPos = L'\0'; // no room for any digits to the right of the decimal point, just truncate it at the "."
+ }
+
+ if (pSuffix != NULL)
+ {
+#ifdef WIN32
+ int retVal = V_snwprintf( textBuffer, textBufferLen, L"%s%s", textBuffer, pSuffix );
+#else
+ int retVal = V_snwprintf( textBuffer, textBufferLen, L"%S%S", textBuffer, pSuffix );
+#endif
+
+ if ( retVal < 0 )
+ {
+ Msg("ConvertNumberToMantissaSuffixForm(): unable to add suffix %S for value %f (buffer size was %i)\n", pSuffix, fNum, textBufferLen);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+CStatsSummary::CStatsSummary(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog"),
+ m_StatImageMap(DefLessFunc(CSStatType_t))
+{
+ m_iFixedWidth = 900; // Give this an initial value in order to set a proper size
+ SetBounds(0, 0, 900, 780);
+ SetMinimumSize(256, 780);
+
+ m_pStatCard = new StatCard(this, "ignored");
+
+ m_pImageList = NULL;
+ m_iDefaultWeaponImage = -1;
+ m_iDefaultMapImage = -1;
+
+ m_pImagePanelFavWeapon = new ImagePanel(this, "FavoriteWeaponImage");
+ m_pImagePanelLastMapFavWeapon = new ImagePanel(this, "FavWeaponIcon");
+ m_pImagePanelFavMap = new ImagePanel(this, "FavoriteMapImage");
+
+ //Setup the recent achievement list by adding all achieved achievements to the list
+ m_pRecentAchievementsList = new vgui::PanelListPanel(this, "RecentAchievementsListPanel");
+ m_pRecentAchievementsList->SetFirstColumnWidth(0);
+
+ ListenForGameEvent( "player_stats_updated" );
+ ListenForGameEvent( "achievement_earned_local" );
+
+ m_bRecentAchievementsDirty = true;
+ m_bStatsDirty = true;
+}
+
+CStatsSummary::~CStatsSummary()
+{
+ if (m_pRecentAchievementsList)
+ {
+ m_pRecentAchievementsList->DeleteAllItems();
+ }
+
+ delete m_pRecentAchievementsList;
+ delete m_pImageList;
+}
+
+void CStatsSummary::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ LoadControlSettings("Resource/UI/CSStatsSummary.res");
+
+ SetBgColor(Color(86,86,86,255));
+
+ if (m_pImageList)
+ delete m_pImageList;
+ m_pImageList = new ImageList(false);
+
+ if (m_pImageList)
+ {
+ //Load defaults
+ m_iDefaultWeaponImage = m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/defaultweapon", true));
+ m_iDefaultMapImage = m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_generic_map", true));
+
+ //load weapon images
+ m_StatImageMap.Insert(CSSTAT_KILLS_DEAGLE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/deserteagle", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_USP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/usp45", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_GLOCK, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/glock18", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_P228, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/p228", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_ELITE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/elites", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_FIVESEVEN, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/fiveseven", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_AWP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/awp", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_AK47, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/ak47", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_M4A1, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m4a1", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_AUG, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/aug", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_SG552, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/sg552", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_SG550, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/sg550", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_GALIL, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/galil", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_FAMAS, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/famas", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_SCOUT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/scout", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_G3SG1, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/g3sg1", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_P90, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/p90", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_MP5NAVY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/mp5", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_TMP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/tmp", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_MAC10, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/mac10", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_UMP45, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/ump45", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_M3, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m3", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_XM1014, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/xm1014", true)));
+ m_StatImageMap.Insert(CSSTAT_KILLS_M249, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m249", true)));
+
+ //load map images
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_ASSAULT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_assault", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_COMPOUND, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_compound", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_HAVANA, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_havana", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_ITALY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_italy", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_MILITIA, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_militia", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_OFFICE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_office", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_AZTEC, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_aztec", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_CBBLE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_cbble", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_CHATEAU, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_chateau", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_DUST2, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_dust2", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_DUST, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_dust", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_INFERNO, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_inferno", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_NUKE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_nuke", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PIRANESI, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_piranesi", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PORT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_port", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PRODIGY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_prodigy", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_TIDES, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_tides", true)));
+ m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_TRAIN, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_train", true)));
+ }
+}
+//----------------------------------------------------------
+// Get the width we're going to lock at
+//----------------------------------------------------------
+void CStatsSummary::ApplySettings(KeyValues *pResourceData)
+{
+ m_iFixedWidth = pResourceData->GetInt("wide", 512);
+
+ BaseClass::ApplySettings(pResourceData);
+}
+
+//----------------------------------------------------------
+// Preserve our width to the one in the .res file
+//----------------------------------------------------------
+void CStatsSummary::OnSizeChanged(int newWide, int newTall)
+{
+ // Lock the width, but allow height scaling
+ if (newWide != m_iFixedWidth)
+ {
+ SetSize(m_iFixedWidth, newTall);
+ return;
+ }
+
+ BaseClass::OnSizeChanged(newWide, newTall);
+}
+
+
+void CStatsSummary::OnThink()
+{
+ if ( m_bRecentAchievementsDirty )
+ UpdateRecentAchievements();
+
+ if ( m_bStatsDirty )
+ UpdateStatsData();
+}
+
+
+void CStatsSummary::OnPageShow()
+{
+ UpdateStatsData();
+ UpdateRecentAchievements();
+}
+
+//----------------------------------------------------------
+// Update all of the stats displays
+//----------------------------------------------------------
+void CStatsSummary::UpdateStatsData()
+{
+ UpdateStatsSummary();
+ UpdateKillHistory();
+ UpdateFavoriteWeaponData();
+ UpdateMapsData();
+
+
+ UpdateLastMatchStats();
+ m_pStatCard->UpdateInfo();
+
+ m_bStatsDirty = false;
+}
+
+//----------------------------------------------------------
+// Update the stats located in the stats summary section
+//----------------------------------------------------------
+void CStatsSummary::UpdateStatsSummary()
+{
+ DisplayCompressedLocalizedStat(CSSTAT_ROUNDS_PLAYED, "roundsplayed");
+ DisplayCompressedLocalizedStat(CSSTAT_ROUNDS_WON, "roundswon");
+ DisplayCompressedLocalizedStat(CSSTAT_SHOTS_HIT, "shotshit");
+ DisplayCompressedLocalizedStat(CSSTAT_SHOTS_FIRED, "shotsfired");
+
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+
+ //Calculate Win Ratio
+ int wins = g_CSClientGameStats.GetStatById(CSSTAT_ROUNDS_WON).iStatValue;
+ int rounds = g_CSClientGameStats.GetStatById(CSSTAT_ROUNDS_PLAYED).iStatValue;
+ float winRatio = 0;
+ if (rounds > 0)
+ {
+ winRatio = ((float)wins / (float)rounds) * 100.0f;
+ }
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", winRatio);
+ SetDialogVariable("winratio", tempWNumString);
+
+
+ //Calculate accuracy
+ int hits = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_HIT).iStatValue;
+ int shots = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_FIRED).iStatValue;
+ float accuracy = 0;
+ if (shots > 0)
+ {
+ accuracy = ((float)hits / (float)shots) * 100.0f;
+ }
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", accuracy);
+ SetDialogVariable("hitratio", tempWNumString);
+}
+
+//----------------------------------------------------------
+// Update the stats located in the stats summary section
+//----------------------------------------------------------
+void CStatsSummary::UpdateKillHistory()
+{
+ DisplayCompressedLocalizedStat(CSSTAT_KILLS, "kills");
+ DisplayCompressedLocalizedStat(CSSTAT_DEATHS, "deaths");
+
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+
+ //Calculate Win Ratio
+ int kills = g_CSClientGameStats.GetStatById(CSSTAT_KILLS).iStatValue;
+ int deaths = g_CSClientGameStats.GetStatById(CSSTAT_DEATHS).iStatValue;
+ float killDeathRatio = 0;
+ if (deaths > 0)
+ {
+ killDeathRatio = (float)kills / (float)deaths;
+ }
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", killDeathRatio);
+ SetDialogVariable("killdeathratio", tempWNumString);
+}
+//----------------------------------------------------------
+// Update the stats located in the favorite weapon section
+//----------------------------------------------------------
+void CStatsSummary::UpdateFavoriteWeaponData()
+{
+ // First set the image to the favorite weapon
+ if (m_pImageList)
+ {
+ //start with a dummy stat
+ const WeaponName_StatId* pFavoriteWeaponStatEntry = NULL;
+
+ //Find the weapon stat with the most kills
+ int numKills = 0;
+ for (int i = 0; WeaponName_StatId_Table[i].killStatId != CSSTAT_UNDEFINED; ++i)
+ {
+ // ignore weapons with no hit counts (knife and grenade)
+ if (WeaponName_StatId_Table[i].hitStatId == CSSTAT_UNDEFINED )
+ continue;
+
+ const WeaponName_StatId& weaponStatEntry = WeaponName_StatId_Table[i];
+ PlayerStatData_t stat = g_CSClientGameStats.GetStatById(weaponStatEntry.killStatId);
+ if (stat.iStatValue > numKills)
+ {
+ pFavoriteWeaponStatEntry = &weaponStatEntry;
+ numKills = stat.iStatValue;
+ }
+ }
+
+ if (pFavoriteWeaponStatEntry)
+ {
+ CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)pFavoriteWeaponStatEntry->killStatId);
+ if (m_StatImageMap.IsValidIndex(idx))
+ {
+ m_pImagePanelFavWeapon->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
+ }
+
+ DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->hitStatId, "weaponhits", "#GameUI_Stats_WeaponShotsHit");
+ DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->shotStatId, "weaponshotsfired", "#GameUI_Stats_WeaponShotsFired");
+ DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->killStatId, "weaponkills", "#GameUI_Stats_WeaponKills");
+
+ //Calculate accuracy
+ int kills = g_CSClientGameStats.GetStatById(pFavoriteWeaponStatEntry->killStatId).iStatValue;
+ int shots = g_CSClientGameStats.GetStatById(pFavoriteWeaponStatEntry->shotStatId).iStatValue;
+ float killsPerShot = 0;
+ if (shots > 0)
+ {
+ killsPerShot = (float)kills / (float)shots;
+ }
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", (killsPerShot));
+ DisplayFormattedLabel("#GameUI_Stats_WeaponKillRatio", tempWNumString, "weaponkillratio");
+ }
+ else
+ {
+ if (m_iDefaultWeaponImage != -1)
+ {
+ m_pImagePanelFavWeapon->SetImage(m_pImageList->GetImage(m_iDefaultWeaponImage));
+ }
+ DisplayFormattedLabel("#GameUI_Stats_WeaponShotsHit", L"0", "weaponhits");
+ DisplayFormattedLabel("#GameUI_Stats_WeaponShotsFired", L"0", "weaponshotsfired");
+ DisplayFormattedLabel("#GameUI_Stats_WeaponKills", L"0", "weaponkills");
+ DisplayFormattedLabel("#GameUI_Stats_WeaponKillRatio", L"0", "weaponkillratio");
+ }
+ }
+}
+
+//----------------------------------------------------------
+// Update the stats located in the favorite weapon section
+//----------------------------------------------------------
+void CStatsSummary::UpdateMapsData()
+{
+ //start with a dummy stat
+ const MapName_MapStatId* pFavoriteMapStat = NULL;
+ int numRounds = 0;
+ for (int i = 0; MapName_StatId_Table[i].statWinsId != CSSTAT_UNDEFINED; ++i)
+ {
+ const MapName_MapStatId& mapStatId = MapName_StatId_Table[i];
+ PlayerStatData_t stat = g_CSClientGameStats.GetStatById(mapStatId.statRoundsId);
+ if (stat.iStatValue > numRounds)
+ {
+ pFavoriteMapStat = &mapStatId;
+ numRounds = stat.iStatValue;
+ }
+ }
+
+ if (pFavoriteMapStat)
+ {
+ CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)pFavoriteMapStat->statWinsId);
+ if (m_StatImageMap.IsValidIndex(idx))
+ {
+ m_pImagePanelFavMap->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
+ }
+
+ // map name
+ SetDialogVariable("mapname", pFavoriteMapStat->szMapName);
+
+ // rounds played
+ DisplayCompressedLocalizedStat(pFavoriteMapStat->statRoundsId,"mapplayed", "#GameUI_Stats_MapPlayed");
+ DisplayCompressedLocalizedStat(pFavoriteMapStat->statWinsId, "mapwins", "#GameUI_Stats_MapWins");
+
+ //Calculate Win Ratio
+ int wins = g_CSClientGameStats.GetStatById(pFavoriteMapStat->statWinsId).iStatValue;
+ int rounds = g_CSClientGameStats.GetStatById(pFavoriteMapStat->statRoundsId).iStatValue;
+ float winRatio = 0;
+ if (rounds > 0)
+ {
+ winRatio = ((float)wins / (float)rounds) * 100.0f;
+ }
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", winRatio);
+ DisplayFormattedLabel("#GameUI_Stats_MapWinRatio", tempWNumString, "mapwinratio");
+ }
+ else
+ {
+ if (m_iDefaultMapImage != -1)
+ {
+ m_pImagePanelFavMap->SetImage(m_pImageList->GetImage(m_iDefaultMapImage));
+ }
+ SetDialogVariable("mapname", L"");
+ DisplayFormattedLabel("#GameUI_Stats_MapPlayed", L"0", "mapplayed");
+ DisplayFormattedLabel("#GameUI_Stats_MapWins", L"0", "mapwins");
+ DisplayFormattedLabel("#GameUI_Stats_MapWinRatio", L"0", "mapwinratio");
+ }
+}
+
+int CStatsSummary::AchivementDateSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight )
+{
+ if (!pLeft || !pRight || !(*pLeft) || ! (*pRight))
+ {
+ return 0;
+ }
+
+ if ((*pLeft)->GetSortKey() < (*pRight)->GetSortKey())
+ {
+ return 1;
+ }
+ else if ((*pLeft)->GetSortKey() > (*pRight)->GetSortKey())
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void CStatsSummary::UpdateRecentAchievements()
+{
+ CUtlVector<CCSBaseAchievement*> sortedAchivementList;
+
+ //Get a list of all the achievements that have been earned
+ int iCount = g_AchievementMgrCS.GetAchievementCount();
+ sortedAchivementList.EnsureCapacity(iCount);
+
+ for (int i = 0; i < iCount; ++i)
+ {
+ CCSBaseAchievement* pAchievement = (CCSBaseAchievement*)g_AchievementMgrCS.GetAchievementByIndex(i);
+ if (pAchievement && pAchievement->IsAchieved())
+ {
+ sortedAchivementList.AddToTail(pAchievement);
+ }
+ }
+
+ //Sort the earned achievements by time and date earned.
+ sortedAchivementList.Sort(AchivementDateSortPredicate);
+
+ //Clear the UI list
+ m_pRecentAchievementsList->DeleteAllItems();
+
+ // Add each achievement in the sorted list as a panel.
+ int numPanelsToAdd = MIN(maxRecentAchievementToDisplay, sortedAchivementList.Count());
+ for ( int i = 0; i < numPanelsToAdd; i++ )
+ {
+ CCSBaseAchievement* pAchievement = sortedAchivementList[i];
+ if (pAchievement)
+ {
+ CAchievementsPageItemPanel *achievementItemPanel = new CAchievementsPageItemPanel(m_pRecentAchievementsList, "AchievementDialogItemPanel");
+ achievementItemPanel->SetAchievementInfo(pAchievement);
+
+ // force all our new panel to have the correct internal layout and size so that our parent container can layout properly
+ achievementItemPanel->InvalidateLayout(true, true);
+
+ m_pRecentAchievementsList->AddItem(NULL, achievementItemPanel);
+ }
+ }
+
+ m_bRecentAchievementsDirty = false;
+}
+
+void CStatsSummary::UpdateLastMatchStats()
+{
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_T_ROUNDS_WON, "lastmatchtwins", "#GameUI_Stats_LastMatch_TWins");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_CT_ROUNDS_WON, "lastmatchctwins", "#GameUI_Stats_LastMatch_CTWins");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_ROUNDS_WON, "lastmatchwins", "#GameUI_Stats_LastMatch_RoundsWon");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_MAX_PLAYERS, "lastmatchmaxplayers", "#GameUI_Stats_LastMatch_MaxPlayers");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_MVPS, "lastmatchstars", "#GameUI_Stats_LastMatch_MVPS");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_KILLS, "lastmatchkills", "#GameUI_Stats_WeaponKills");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DEATHS, "lastmatchdeaths", "#GameUI_Stats_LastMatch_Deaths");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DAMAGE, "lastmatchtotaldamage", "#GameUI_Stats_LastMatch_Damage");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DOMINATIONS, "lastmatchdominations", "#GameUI_Stats_LastMatch_Dominations");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_REVENGES, "lastmatchrevenges", "#GameUI_Stats_LastMatch_Revenges");
+
+ UpdateLastMatchFavoriteWeaponStats();
+
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+
+ //Calculate Kill:Death ratio
+ int deaths = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_DEATHS).iStatValue;
+ int kills = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_KILLS).iStatValue;
+ float killDeathRatio = deaths;
+ if (deaths != 0)
+ {
+ killDeathRatio = (float)kills / (float)deaths;
+ }
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", killDeathRatio);
+ DisplayFormattedLabel("#GameUI_Stats_LastMatch_KDRatio", tempWNumString, "lastmatchkilldeathratio");
+
+ //Calculate cost per kill
+ PlayerStatData_t statMoneySpent = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_MONEYSPENT);
+ int costPerKill = 0;
+ if (kills > 0)
+ {
+ costPerKill = statMoneySpent.iStatValue / kills;
+ }
+ ConvertNumberToMantissaSuffixForm(costPerKill, tempWNumString, STAT_NUM_ARRAY_LENGTH);
+ DisplayFormattedLabel("#GameUI_Stats_LastMatch_MoneySpentPerKill", tempWNumString, "lastmatchmoneyspentperkill");
+}
+
+void CStatsSummary::UpdateLastMatchFavoriteWeaponStats()
+{
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+
+ PlayerStatData_t statFavWeaponId = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_ID);
+ const WeaponName_StatId& favoriteWeaponStat = GetWeaponTableEntryFromWeaponId((CSWeaponID)statFavWeaponId.iStatValue);
+
+ // If we have a valid weapon use it's data; otherwise use nothing. We check the shot ID to make sure it is a weapon with bullets.
+ if (favoriteWeaponStat.hitStatId != CSSTAT_UNDEFINED)
+ {
+ // Set the image and (non-copyright) name of this weapon
+ CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)favoriteWeaponStat.killStatId);
+ if (m_StatImageMap.IsValidIndex(idx))
+ {
+ m_pImagePanelLastMapFavWeapon->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
+ }
+
+ const wchar_t* tempName = WeaponIDToDisplayName(favoriteWeaponStat.weaponId);
+ if (tempName)
+ {
+ SetDialogVariable("lastmatchfavweaponname", tempName);
+ }
+ else
+ {
+ SetDialogVariable("lastmatchfavweaponname", L"");
+ }
+
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_FAVWEAPON_KILLS, "lastmatchfavweaponkills", "#GameUI_Stats_WeaponKills");
+ DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_FAVWEAPON_HITS, "lastmatchfavweaponhits", "#GameUI_Stats_WeaponShotsHit");
+
+ int shots = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_SHOTS).iStatValue;
+ int hits = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_HITS).iStatValue;
+ float accuracy = 0.0f;
+ if (shots != 0)
+ {
+ accuracy = ((float)hits / (float)shots) * 100.0f;
+ }
+ V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", accuracy);
+ DisplayFormattedLabel("#GameUI_Stats_LastMatch_FavWeaponAccuracy", tempWNumString, "lastmatchfavweaponaccuracy");
+ }
+ else
+ {
+ if (m_iDefaultWeaponImage != -1)
+ {
+ m_pImagePanelLastMapFavWeapon->SetImage(m_pImageList->GetImage(m_iDefaultWeaponImage));
+ }
+
+
+ //Set this label to diferent text, indicating that there is not a favorite weapon
+ SetDialogVariable("lastmatchfavweaponname", g_pVGuiLocalize->Find("#GameUI_Stats_LastMatch_NoFavWeapon"));
+
+ DisplayFormattedLabel("#GameUI_Stats_WeaponKills", L"0", "lastmatchfavweaponkills");
+ DisplayFormattedLabel("#GameUI_Stats_WeaponShotsHit", L"0", "lastmatchfavweaponhits");
+ DisplayFormattedLabel("#GameUI_Stats_LastMatch_FavWeaponAccuracy", L"0", "lastmatchfavweaponaccuracy");
+ }
+}
+
+void CStatsSummary::FireGameEvent( IGameEvent *event )
+{
+ const char *type = event->GetName();
+
+ if ( 0 == Q_strcmp( type, "achievement_earned_local" ) )
+ {
+ m_bRecentAchievementsDirty = true;
+ }
+
+ else if ( 0 == Q_strcmp( type, "player_stats_updated" ) )
+ {
+ m_bStatsDirty = true;
+ }
+}
+
+void CStatsSummary::DisplayCompressedLocalizedStat(CSStatType_t stat, const char* dialogVariable, const char* localizationToken /* = NULL */)
+{
+ wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
+ int statValue = g_CSClientGameStats.GetStatById(stat).iStatValue;
+ ConvertNumberToMantissaSuffixForm(statValue, tempWNumString, STAT_NUM_ARRAY_LENGTH);
+ if (localizationToken)
+ {
+ DisplayFormattedLabel(localizationToken, tempWNumString, dialogVariable);
+ }
+ else
+ {
+ SetDialogVariable(dialogVariable, tempWNumString);
+ }
+}
+
+
+void CStatsSummary::DisplayFormattedLabel( const char* localizationToken, const wchar_t* valueText, const char* dialogVariable )
+{
+ wchar_t tempWStatString[256];
+ g_pVGuiLocalize->ConstructString(tempWStatString, sizeof(tempWStatString),
+ g_pVGuiLocalize->Find(localizationToken), 1, valueText);
+ SetDialogVariable(dialogVariable, tempWStatString);
+}
diff --git a/game/client/cstrike/VGUI/stats_summary.h b/game/client/cstrike/VGUI/stats_summary.h
new file mode 100644
index 0000000..e4e0c41
--- /dev/null
+++ b/game/client/cstrike/VGUI/stats_summary.h
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSSTATSSUMMARY_H
+#define CSSTATSSUMMARY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/PropertyPage.h"
+#include "vgui_controls/Button.h"
+#include "c_cs_player.h"
+#include "cs_gamestats_shared.h"
+#include "achievements_page.h"
+#include "GameEventListener.h"
+#include "utlmap.h"
+
+class IAchievement;
+class IScheme;
+class CAchievementsPageGroupPanel;
+class StatCard;
+class CCSBaseAchievement;
+
+class CStatsSummary : public vgui::PropertyPage, public CGameEventListener
+{
+ DECLARE_CLASS_SIMPLE ( CStatsSummary, vgui::PropertyPage );
+
+public:
+ CStatsSummary( vgui::Panel *parent, const char *name );
+ ~CStatsSummary();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void OnSizeChanged( int newWide, int newTall );
+ virtual void FireGameEvent( IGameEvent *event );
+
+ virtual void OnThink();
+ virtual void OnPageShow();
+
+ void UpdateStatsData();
+ void UpdateStatsSummary();
+ void UpdateKillHistory();
+ void UpdateFavoriteWeaponData();
+ void UpdateMapsData();
+ void UpdateRecentAchievements();
+ void UpdateLastMatchStats();
+
+ void UpdateLastMatchFavoriteWeaponStats();
+
+private:
+
+ static int AchivementDateSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight);
+ void DisplayCompressedLocalizedStat(CSStatType_t stat, const char* dialogVariable, const char* localizationToken = NULL);
+ void DisplayFormattedLabel(const char* localizationToken, const wchar_t* valueText, const char* dialogVariable);
+
+ int m_iFixedWidth;
+ int m_iDefaultWeaponImage;
+ int m_iDefaultMapImage;
+
+ vgui::Label* m_pLabelRoundsPlayed;
+ vgui::Label* m_pLabelRoundsWon;
+ vgui::ImagePanel* m_pImagePanelFavWeapon;
+ vgui::ImagePanel* m_pImagePanelLastMapFavWeapon;
+ vgui::ImagePanel* m_pImagePanelFavMap;
+
+ vgui::ImageList *m_pImageList;
+
+ vgui::PanelListPanel *m_pRecentAchievementsList;
+
+ StatCard* m_pStatCard;
+
+ bool m_bRecentAchievementsDirty;
+ bool m_bStatsDirty;
+
+ CUtlMap<CSStatType_t, int> m_StatImageMap;
+};
+#endif // CSSTATSSUMMARY_H \ No newline at end of file
diff --git a/game/client/cstrike/VGUI/win_panel_round.cpp b/game/client/cstrike/VGUI/win_panel_round.cpp
new file mode 100644
index 0000000..7c05f26
--- /dev/null
+++ b/game/client/cstrike/VGUI/win_panel_round.cpp
@@ -0,0 +1,470 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Create and display a win panel at the end of a round displaying interesting stats and info about the round.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "win_panel_round.h"
+#include "vgui_controls/AnimationController.h"
+#include "iclientmode.h"
+#include "c_playerresource.h"
+#include <vgui_controls/Label.h>
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <vgui/ISystem.h>
+#include "fmtstr.h"
+#include "cs_gamestats_shared.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+ConVar cl_round_win_fade_time( "cl_round_win_fade_time", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
+
+DECLARE_HUDELEMENT_DEPTH( WinPanel_Round, 1 ); // 1 is foreground
+extern const wchar_t *LocalizeFindSafe( const char *pTokenName );
+
+
+// helper function for converting wstrings to upper-case inline
+// NB: this returns a pointer to a static buffer
+wchar_t* UpperCaseWideString( const wchar_t* wszSource )
+{
+ static wchar_t wszBuffer[256];
+ V_wcsncpy(wszBuffer, wszSource, sizeof(wszBuffer));
+ V_wcsupr(wszBuffer);
+ return wszBuffer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+WinPanel_Round::WinPanel_Round( const char *pElementName ) :
+ BorderedPanel( NULL, pElementName ),
+ CHudElement( pElementName ),
+ m_bIsFading(false),
+ m_fFadeBeginTime(0.0f)
+{
+ SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
+ SetParent(g_pClientMode->GetViewport());
+
+ SetScheme( "ClientScheme" );
+
+ RegisterForRenderGroup( "hide_for_scoreboard" );
+
+ m_bShouldBeVisible = false;
+}
+
+WinPanel_Round::~WinPanel_Round()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void WinPanel_Round::Reset()
+{
+ Hide();
+}
+
+void WinPanel_Round::Init()
+{
+ CHudElement::Init();
+
+ // listen for events
+ ListenForGameEvent( "round_end" );
+ ListenForGameEvent( "round_start" );
+ ListenForGameEvent( "cs_win_panel_round" );
+ ListenForGameEvent( "cs_win_panel_match" );
+ ListenForGameEvent( "round_mvp" );
+
+ InitLayout();
+
+ m_bShouldBeVisible = false;
+ m_bShowTimerDefend = false;
+ m_bShowTimerAttack = false;
+}
+
+
+void WinPanel_Round::InitLayout()
+{
+ // reload control settings when resolution changes to force update of proportional layout
+ LoadControlSettings("Resource/UI/Win_Round.res");
+
+ CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
+ pMVP_Avatar->SetDefaultAvatar(scheme()->GetImage( CSTRIKE_DEFAULT_AVATAR, true));
+ pMVP_Avatar->SetShouldDrawFriendIcon(false);
+}
+
+
+void WinPanel_Round::VidInit()
+{
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [Forrest] Allow win panel to be turned off on client
+//=============================================================================
+ConVar cl_nowinpanel(
+ "cl_nowinpanel",
+ "0",
+ FCVAR_ARCHIVE,
+ "Turn on/off win panel on client"
+ );
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+void WinPanel_Round::FireGameEvent( IGameEvent* event )
+{
+ const char *pEventName = event->GetName();
+
+ if ( Q_strcmp( "round_end", pEventName ) == 0 )
+ {
+ }
+ else if ( Q_strcmp( "round_start", pEventName ) == 0 )
+ {
+ Hide();
+ }
+ else if( Q_strcmp( "cs_win_panel_match", pEventName ) == 0 )
+ {
+ Hide();
+ }
+ else if( Q_strcmp( "round_mvp", pEventName ) == 0 )
+ {
+ C_BasePlayer *basePlayer = UTIL_PlayerByUserId( event->GetInt( "userid" ) );
+ CSMvpReason_t mvpReason = (CSMvpReason_t)event->GetInt( "reason" );
+
+ if( basePlayer )
+ {
+ SetMVP( ToCSPlayer( basePlayer ), mvpReason );
+ }
+ }
+ else if ( Q_strcmp( "cs_win_panel_round", pEventName ) == 0 )
+ {
+ /*
+ "show_timer_defend" "bool"
+ "show_timer_attack" "bool"
+ "timer_time" "int"
+
+ "final_event" "byte" // 0 - no event, 1 - bomb exploded, 2 - flag capped, 3 - timer expired
+
+ "funfact_type" "byte" //WINPANEL_FUNFACT in cs_shareddef.h
+ "funfact_player" "byte"
+ "funfact_data1" "long"
+ "funfact_data2" "long"
+ "funfact_data3" "long"
+ */
+
+ if ( !g_PR )
+ return;
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [Forrest] Check if win panel is disabled.
+ //=============================================================================
+ static ConVarRef sv_nowinpanel( "sv_nowinpanel" );
+ if ( sv_nowinpanel.GetBool() || cl_nowinpanel.GetBool() )
+ return;
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ m_bShowTimerDefend = event->GetBool( "show_timer_defend" );
+ m_bShowTimerAttack = event->GetBool( "show_timer_attack" );
+ int iTimerTime = event->GetInt( "timer_time" );
+
+ int minutes = clamp( iTimerTime / 60, 0, 99 );
+ int seconds = clamp( iTimerTime % 60, 0, 59 );
+
+ wchar_t time[8];
+ _snwprintf( time, ARRAYSIZE( time ), L"%d:%02d", minutes, seconds );
+
+ SetDialogVariable("TIMER_TEXT", time);
+
+ // Final Fun Fact
+ SetFunFactLabel( L"");
+ int iFunFactPlayer = event->GetInt("funfact_player");
+ const char* funfactToken = event->GetString("funfact_token", "");
+
+ if (strlen(funfactToken) != 0)
+ {
+ wchar_t funFactText[256];
+ wchar_t playerText[64];
+ wchar_t dataText1[8], dataText2[8], dataText3[8];
+ int param1 = event->GetInt("funfact_data1");
+ int param2 = event->GetInt("funfact_data2");
+ int param3 = event->GetInt("funfact_data3");
+ if ( iFunFactPlayer >= 1 && iFunFactPlayer <= MAX_PLAYERS )
+ {
+ const char* playerName = g_PR->GetPlayerName( iFunFactPlayer );
+ if( playerName && Q_strcmp( playerName, PLAYER_UNCONNECTED_NAME ) != 0 && Q_strcmp( playerName, PLAYER_ERROR_NAME ) != 0 )
+ {
+ V_strtowcs( g_PR->GetPlayerName( iFunFactPlayer ), 64, playerText, sizeof( playerText ) );
+ }
+ else
+ {
+#ifdef WIN32
+ _snwprintf( playerText, ARRAYSIZE( playerText ), L"%s", LocalizeFindSafe( "#winpanel_former_player" ) );
+#else
+ _snwprintf( playerText, ARRAYSIZE( playerText ), L"%S", LocalizeFindSafe( "#winpanel_former_player" ) );
+#endif
+ }
+ }
+ else
+ {
+ _snwprintf( playerText, ARRAYSIZE( playerText ), L"" );
+ }
+ _snwprintf( dataText1, ARRAYSIZE( dataText1 ), L"%i", param1 );
+ _snwprintf( dataText2, ARRAYSIZE( dataText2 ), L"%i", param2 );
+ _snwprintf( dataText3, ARRAYSIZE( dataText3 ), L"%i", param3 );
+ g_pVGuiLocalize->ConstructString( funFactText, sizeof(funFactText), (wchar_t *)LocalizeFindSafe(funfactToken), 4,
+ playerText, dataText1, dataText2, dataText3 );
+ SetFunFactLabel(funFactText);
+ }
+
+ int iEndEvent = event->GetInt( "final_event" );
+
+ //Map the round end events onto localized strings
+ const char* endEventToString[RoundEndReason_Count];
+ V_memset(endEventToString, 0, sizeof(endEventToString));
+
+ //terrorist win events
+ endEventToString[Target_Bombed] = "#winpanel_end_target_bombed";
+ endEventToString[VIP_Assassinated] = "#winpanel_end_vip_assassinated";
+ endEventToString[Terrorists_Escaped] = "#winpanel_end_terrorists_escaped";
+ endEventToString[Terrorists_Win] = "#winpanel_end_terrorists__kill";
+ endEventToString[Hostages_Not_Rescued] = "#winpanel_end_hostages_not_rescued";
+ endEventToString[VIP_Not_Escaped] = "#winpanel_end_vip_not_escaped";
+
+ //CT win events
+ endEventToString[VIP_Escaped] = "#winpanel_end_vip_escaped";
+ endEventToString[CTs_PreventEscape] = "#winpanel_end_cts_prevent_escape";
+ endEventToString[Escaping_Terrorists_Neutralized] = "#winpanel_end_escaping_terrorists_neutralized";
+ endEventToString[Bomb_Defused] = "#winpanel_end_bomb_defused";
+ endEventToString[CTs_Win] = "#winpanel_end_cts_win";
+ endEventToString[All_Hostages_Rescued] = "#winpanel_end_all_hostages_rescued";
+ endEventToString[Target_Saved] = "#winpanel_end_target_saved";
+ endEventToString[Terrorists_Not_Escaped] = "#winpanel_end_terrorists_not_escaped";
+
+ //We don't show a round end panel for these
+ endEventToString[Game_Commencing] = "";
+ endEventToString[Round_Draw] = "";
+
+ const wchar_t* wszEventMessage = NULL;
+ if(iEndEvent >=0 && iEndEvent < RoundEndReason_Count)
+ wszEventMessage = LocalizeFindSafe(endEventToString[iEndEvent]);
+
+ if ( wszEventMessage != NULL )
+ {
+ SetDialogVariable("WIN_DESCRIPTION", UpperCaseWideString(wszEventMessage));
+ }
+ else
+ {
+ SetDialogVariable("WIN_DESCRIPTION", "");
+ }
+
+ Label* pWinLabel = dynamic_cast<Label*>(FindChildByName("WinLabel"));
+ switch(iEndEvent)
+ {
+ case Target_Bombed:
+ case VIP_Assassinated:
+ case Terrorists_Escaped:
+ case Terrorists_Win:
+ case Hostages_Not_Rescued:
+ case VIP_Not_Escaped:
+ pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_t_win")));
+ pWinLabel->SetFgColor(Color(184,0,0,255));
+ break;
+
+ case VIP_Escaped:
+ case CTs_PreventEscape:
+ case Escaping_Terrorists_Neutralized:
+ case Bomb_Defused:
+ case CTs_Win:
+ case All_Hostages_Rescued:
+ case Target_Saved:
+ case Terrorists_Not_Escaped:
+ pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_ct_win")));
+ pWinLabel->SetFgColor(Color(71,152,237,255));
+ break;
+
+ case Round_Draw:
+ pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_draw")));
+ pWinLabel->SetFgColor(Color(204,204,204,255));
+ break;
+ }
+
+ //[tj] We set the icon to the generic one right before we show it.
+ // The expected result is that we replace it immediately with
+ // the round MVP. if there is none, we just use the generic.
+ SetMVP( NULL, CSMVP_UNDEFINED );
+
+ Show();
+ }
+}
+
+void WinPanel_Round::SetMVP( C_CSPlayer* pPlayer, CSMvpReason_t reason )
+{
+ CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
+
+ if ( pMVP_Avatar )
+ {
+ pMVP_Avatar->ClearAvatar();
+ }
+
+ //First set the text to the name of the player
+ //=============================================================================
+ // HPE_BEGIN:
+ // [Forrest] Allow MVP to be turned off for a server
+ //=============================================================================
+ bool isThereAnMVP = ( pPlayer != NULL );
+ if ( isThereAnMVP )
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+ {
+
+ const char* mvpReasonToken = NULL;
+ switch ( reason )
+ {
+ case CSMVP_ELIMINATION:
+ mvpReasonToken = "winpanel_mvp_award_kills";
+ break;
+ case CSMVP_BOMBPLANT:
+ mvpReasonToken = "winpanel_mvp_award_bombplant";
+ break;
+ case CSMVP_BOMBDEFUSE:
+ mvpReasonToken = "winpanel_mvp_award_bombdefuse";
+ break;
+ case CSMVP_HOSTAGERESCUE:
+ mvpReasonToken = "winpanel_mvp_award_rescue";
+ break;
+ default:
+ mvpReasonToken = "winpanel_mvp_award";
+ break;
+ }
+
+ wchar_t wszBuf[256], wszPlayerName[64];
+ g_pVGuiLocalize->ConvertANSIToUnicode(UTIL_SafeName(pPlayer->GetPlayerName()), wszPlayerName, sizeof(wszPlayerName));
+
+ wchar_t *pReason = (wchar_t *)LocalizeFindSafe( mvpReasonToken );
+ if ( !pReason )
+ {
+ pReason = L"%s1";
+ }
+
+ g_pVGuiLocalize->ConstructString( wszBuf, sizeof( wszBuf ), pReason, 1, wszPlayerName );
+ SetDialogVariable( "MVP_TEXT", wszBuf );
+
+ player_info_t pi;
+ if ( engine->GetPlayerInfo(pPlayer->entindex(), &pi) )
+ {
+ if ( pMVP_Avatar )
+ {
+ pMVP_Avatar->SetDefaultAvatar( GetDefaultAvatarImage( pPlayer ) );
+ pMVP_Avatar->SetPlayer( pPlayer, k_EAvatarSize64x64 );
+ }
+ }
+ }
+ else
+ {
+ SetDialogVariable( "MVP_TEXT", "");
+ }
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [Forrest] Allow MVP to be turned off for a server
+ //=============================================================================
+ // The avatar image and its accompanying elements should be hidden if there is no MVP for the round.
+ if ( pMVP_Avatar )
+ {
+ pMVP_Avatar->SetVisible( isThereAnMVP );
+ }
+ ImagePanel* pMVP_AvatarGlow = dynamic_cast<ImagePanel*>(FindChildByName("MVP_AvatarGlow"));
+ if ( pMVP_AvatarGlow )
+ {
+ pMVP_AvatarGlow->SetVisible( isThereAnMVP );
+ }
+ ImagePanel* pMVP_Foreground_Star = dynamic_cast<ImagePanel*>(FindChildByName("MVP_Foreground_Star"));
+ if ( pMVP_Foreground_Star )
+ {
+ pMVP_Foreground_Star->SetVisible( isThereAnMVP );
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+}
+
+void WinPanel_Round::SetFunFactLabel( const wchar *szFunFact )
+{
+ SetDialogVariable( "FUNFACT", szFunFact );
+}
+
+void WinPanel_Round::Show( void )
+{
+ int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
+ if ( iRenderGroup >= 0)
+ {
+ gHUD.LockRenderGroup( iRenderGroup );
+ }
+
+ m_bShouldBeVisible = true;
+ SetAlpha(255);
+ m_bIsFading = false;
+}
+
+void WinPanel_Round::Hide( void )
+{
+ if ( m_bShouldBeVisible && !m_bIsFading )
+ {
+ m_bIsFading = true;
+ m_fFadeBeginTime = gpGlobals->realtime;
+ }
+}
+
+void WinPanel_Round::OnThink()
+{
+ if ( m_bShouldBeVisible && m_bIsFading )
+ {
+ float fAlpha = 1.0f - (gpGlobals->realtime - m_fFadeBeginTime) / cl_round_win_fade_time.GetFloat();
+
+ if (fAlpha >= 0.0f)
+ {
+ SetAlpha(RoundFloatToInt(fAlpha * 255.0f));
+ }
+ else
+ {
+ int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
+ if ( iRenderGroup >= 0 )
+ {
+ gHUD.UnlockRenderGroup( iRenderGroup );
+ }
+ m_bShouldBeVisible = false;
+ SetAlpha(0);
+ m_bIsFading = false;
+ }
+ }
+}
+
+void WinPanel_Round::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetFgColor(Color(251,176,59,255));
+ SetBgColor(Color(0,0,0,212));
+}
+
+void WinPanel_Round::OnScreenSizeChanged( int nOldWide, int nOldTall )
+{
+ BaseClass::OnScreenSizeChanged(nOldWide, nOldTall);
+
+ InitLayout();
+
+
+}
+
+bool WinPanel_Round::ShouldDraw( void )
+{
+ return ( m_bShouldBeVisible && CHudElement::ShouldDraw());
+}
diff --git a/game/client/cstrike/VGUI/win_panel_round.h b/game/client/cstrike/VGUI/win_panel_round.h
new file mode 100644
index 0000000..f5a6d7e
--- /dev/null
+++ b/game/client/cstrike/VGUI/win_panel_round.h
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Create and display a win panel at the end of a round displaying interesting stats and info about the round.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CSWINPANEL_ROUND_H
+#define CSWINPANEL_ROUND_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "VGUI/bordered_panel.h"
+#include <game/client/iviewport.h>
+#include <vgui/IScheme.h>
+#include "hud.h"
+#include "hudelement.h"
+#include "c_cs_player.h"
+#include "vgui_avatarimage.h"
+
+#include "cs_shareddefs.h"
+
+using namespace vgui;
+
+class WinPanel_Round : public BorderedPanel, public CHudElement
+{
+private:
+ DECLARE_CLASS_SIMPLE( WinPanel_Round, BorderedPanel );
+
+public:
+ WinPanel_Round(const char *pElementName);
+ ~WinPanel_Round();
+
+ virtual void Reset();
+ virtual void Init();
+ virtual void VidInit();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void FireGameEvent( IGameEvent * event );
+ virtual bool ShouldDraw( void );
+ virtual void Paint( void ) {};
+ virtual void OnScreenSizeChanged(int nOldWide, int nOldTall);
+
+ virtual void OnThink();
+
+ void InitLayout();
+ void Show();
+ void Hide();
+
+protected:
+ void SetMVP( C_CSPlayer* pPlayer, CSMvpReason_t reason );
+ void SetFunFactLabel( const wchar *szFunFact );
+
+private:
+ bool m_bShowTimerDefend;
+ bool m_bShowTimerAttack;
+
+ bool m_bShouldBeVisible;
+
+ // fade tracking
+ bool m_bIsFading;
+ float m_fFadeBeginTime;
+};
+
+#endif //CSWINPANEL_ROUND_H \ No newline at end of file