This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+431
View File
@@ -0,0 +1,431 @@
//========= 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
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/hl2mp_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 );
}
//-----------------------------------------------------------------------------
+43
View File
@@ -0,0 +1,43 @@
//========= 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 hScheme, int scaledValue );
//-----------------------------------------------------------------------------
#endif // CSBACKGROUND_H
@@ -0,0 +1,653 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "hl2mpclientscoreboard.h"
#include "c_team.h"
#include "c_playerresource.h"
#include "c_hl2mp_player.h"
#include "hl2mp_gamerules.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 "voice_status.h"
using namespace vgui;
#define TEAM_MAXCOUNT 5
// id's of sections used in the scoreboard
enum EScoreboardSections
{
SCORESECTION_COMBINE = 1,
SCORESECTION_REBELS = 2,
SCORESECTION_FREEFORALL = 3,
SCORESECTION_SPECTATOR = 4
};
const int NumSegments = 7;
static int coord[NumSegments+1] = {
0,
1,
2,
3,
4,
6,
9,
10
};
//-----------------------------------------------------------------------------
// Purpose: Konstructor
//-----------------------------------------------------------------------------
CHL2MPClientScoreBoardDialog::CHL2MPClientScoreBoardDialog(IViewPort *pViewPort):CClientScoreBoardDialog(pViewPort)
{
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CHL2MPClientScoreBoardDialog::~CHL2MPClientScoreBoardDialog()
{
}
//-----------------------------------------------------------------------------
// Purpose: Paint background for rounded corners
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::PaintBackground()
{
m_pPlayerList->SetBgColor( Color(0, 0, 0, 0) );
m_pPlayerList->SetBorder(NULL);
int x1, x2, y1, y2;
surface()->DrawSetColor(m_bgColor);
surface()->DrawSetTextColor(m_bgColor);
int wide, tall;
GetSize( wide, tall );
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 );
}
//-----------------------------------------------------------------------------
// Purpose: Paint border for rounded corners
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::PaintBorder()
{
int x1, x2, y1, y2;
surface()->DrawSetColor(m_borderColor);
surface()->DrawSetTextColor(m_borderColor);
int wide, tall;
GetSize( wide, tall );
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 );
}
//-----------------------------------------------------------------------------
// Purpose: Apply scheme settings
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
m_bgColor = GetSchemeColor("SectionedListPanel.BgColor", GetBgColor(), pScheme);
m_borderColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) );
SetBgColor( Color(0, 0, 0, 0) );
SetBorder( pScheme->GetBorder( "BaseBorder" ) );
}
//-----------------------------------------------------------------------------
// Purpose: sets up base sections
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::InitScoreboardSections()
{
m_pPlayerList->SetBgColor( Color(0, 0, 0, 0) );
m_pPlayerList->SetBorder(NULL);
// fill out the structure of the scoreboard
AddHeader();
if ( HL2MPRules()->IsTeamplay() )
{
// add the team sections
AddSection( TYPE_TEAM, TEAM_COMBINE );
AddSection( TYPE_TEAM, TEAM_REBELS );
}
else
{
AddSection( TYPE_TEAM, TEAM_UNASSIGNED );
}
AddSection( TYPE_TEAM, TEAM_SPECTATOR );
}
//-----------------------------------------------------------------------------
// Purpose: resets the scoreboard team info
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::UpdateTeamInfo()
{
if ( g_PR == NULL )
return;
int iNumPlayersInGame = 0;
for ( int j = 1; j <= gpGlobals->maxClients; j++ )
{
if ( g_PR->IsConnected( j ) )
{
iNumPlayersInGame++;
}
}
// update the team sections in the scoreboard
for ( int i = TEAM_SPECTATOR; i < TEAM_MAXCOUNT; i++ )
{
wchar_t *teamName = NULL;
int sectionID = 0;
C_Team *team = GetGlobalTeam(i);
if ( team )
{
sectionID = GetSectionFromTeamNumber( i );
// update team name
wchar_t name[64];
wchar_t string1[1024];
wchar_t wNumPlayers[6];
if ( HL2MPRules()->IsTeamplay() == false )
{
_snwprintf( wNumPlayers, ARRAYSIZE(wNumPlayers), L"%i", iNumPlayersInGame );
#ifdef WIN32
_snwprintf( name, ARRAYSIZE(name), L"%s", g_pVGuiLocalize->Find("#ScoreBoard_Deathmatch") );
#else
_snwprintf( name, ARRAYSIZE(name), L"%S", g_pVGuiLocalize->Find("#ScoreBoard_Deathmatch") );
#endif
teamName = name;
if ( iNumPlayersInGame == 1)
{
g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find("#ScoreBoard_Player"), 2, teamName, wNumPlayers );
}
else
{
g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find("#ScoreBoard_Players"), 2, teamName, wNumPlayers );
}
}
else
{
_snwprintf(wNumPlayers, ARRAYSIZE(wNumPlayers), L"%i", team->Get_Number_Players());
if (!teamName && team)
{
g_pVGuiLocalize->ConvertANSIToUnicode(team->Get_Name(), name, sizeof(name));
teamName = name;
}
if (team->Get_Number_Players() == 1)
{
g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find("#ScoreBoard_Player"), 2, teamName, wNumPlayers );
}
else
{
g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find("#ScoreBoard_Players"), 2, teamName, wNumPlayers );
}
// update stats
wchar_t val[6];
V_snwprintf(val, ARRAYSIZE(val), L"%d", team->Get_Score());
m_pPlayerList->ModifyColumn(sectionID, "frags", val);
if (team->Get_Ping() < 1)
{
m_pPlayerList->ModifyColumn(sectionID, "ping", L"");
}
else
{
V_snwprintf(val, ARRAYSIZE(val), L"%d", team->Get_Ping());
m_pPlayerList->ModifyColumn(sectionID, "ping", val);
}
}
m_pPlayerList->ModifyColumn(sectionID, "name", string1);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: adds the top header of the scoreboars
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::AddHeader()
{
// add the top header
m_pPlayerList->AddSection(0, "");
m_pPlayerList->SetSectionAlwaysVisible(0);
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
m_pPlayerList->AddColumnToSection(0, "name", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH ), hFallbackFont );
m_pPlayerList->AddColumnToSection(0, "class", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_CLASS_WIDTH ) );
m_pPlayerList->AddColumnToSection(0, "frags", "#PlayerScore", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_SCORE_WIDTH ) );
m_pPlayerList->AddColumnToSection(0, "deaths", "#PlayerDeath", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_DEATH_WIDTH ) );
m_pPlayerList->AddColumnToSection(0, "ping", "#PlayerPing", 0 | SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_PING_WIDTH ) );
// m_pPlayerList->AddColumnToSection(0, "voice", "#PlayerVoice", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::HEADER_TEXT| SectionedListPanel::COLUMN_CENTER, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_VOICE_WIDTH ) );
// m_pPlayerList->AddColumnToSection(0, "tracker", "#PlayerTracker", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::HEADER_TEXT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_FRIENDS_WIDTH ) );
}
//-----------------------------------------------------------------------------
// Purpose: Adds a new section to the scoreboard (i.e the team header)
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::AddSection(int teamType, int teamNumber)
{
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
int sectionID = GetSectionFromTeamNumber( teamNumber );
if ( teamType == TYPE_TEAM )
{
m_pPlayerList->AddSection(sectionID, "", StaticPlayerSortFunc);
// setup the columns
m_pPlayerList->AddColumnToSection(sectionID, "name", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH ), hFallbackFont );
m_pPlayerList->AddColumnToSection(sectionID, "class", "" , 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_CLASS_WIDTH ) );
m_pPlayerList->AddColumnToSection(sectionID, "frags", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_SCORE_WIDTH ) );
m_pPlayerList->AddColumnToSection(sectionID, "deaths", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_DEATH_WIDTH ) );
m_pPlayerList->AddColumnToSection(sectionID, "ping", "", SectionedListPanel::COLUMN_RIGHT, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_PING_WIDTH ) );
// set the section to have the team color
if ( teamNumber )
{
if ( GameResources() )
m_pPlayerList->SetSectionFgColor(sectionID, GameResources()->GetTeamColor(teamNumber));
}
m_pPlayerList->SetSectionAlwaysVisible(sectionID);
}
else if ( teamType == TYPE_SPECTATORS )
{
m_pPlayerList->AddSection(sectionID, "");
m_pPlayerList->AddColumnToSection(sectionID, "name", "#Spectators", 0, scheme()->GetProportionalScaledValueEx( GetScheme(), CSTRIKE_NAME_WIDTH ), hFallbackFont );
m_pPlayerList->AddColumnToSection(sectionID, "class", "" , 0, scheme()->GetProportionalScaledValueEx( GetScheme(), 100 ) );
}
}
int CHL2MPClientScoreBoardDialog::GetSectionFromTeamNumber( int teamNumber )
{
switch ( teamNumber )
{
case TEAM_COMBINE:
return SCORESECTION_COMBINE;
case TEAM_REBELS:
return SCORESECTION_REBELS;
case TEAM_SPECTATOR:
return SCORESECTION_SPECTATOR;
default:
return SCORESECTION_FREEFORALL;
}
return SCORESECTION_FREEFORALL;
}
//-----------------------------------------------------------------------------
// Purpose: Adds a new row to the scoreboard, from the playerinfo structure
//-----------------------------------------------------------------------------
bool CHL2MPClientScoreBoardDialog::GetPlayerScoreInfo(int playerIndex, KeyValues *kv)
{
kv->SetInt("playerIndex", playerIndex);
kv->SetInt("team", g_PR->GetTeam( playerIndex ) );
kv->SetString("name", g_PR->GetPlayerName(playerIndex) );
kv->SetInt("deaths", g_PR->GetDeaths( playerIndex ));
kv->SetInt("frags", g_PR->GetPlayerScore( playerIndex ));
kv->SetString("class", "");
if (g_PR->GetPing( playerIndex ) < 1)
{
if ( g_PR->IsFakePlayer( playerIndex ) )
{
kv->SetString("ping", "BOT");
}
else
{
kv->SetString("ping", "");
}
}
else
{
kv->SetInt("ping", g_PR->GetPing( playerIndex ));
}
return true;
}
enum {
MAX_PLAYERS_PER_TEAM = 16,
MAX_SCOREBOARD_PLAYERS = 32
};
struct PlayerScoreInfo
{
int index;
int frags;
int deaths;
bool important;
bool alive;
};
int PlayerScoreInfoSort( const PlayerScoreInfo *p1, const PlayerScoreInfo *p2 )
{
// check local
if ( p1->important )
return -1;
if ( p2->important )
return 1;
// check alive
if ( p1->alive && !p2->alive )
return -1;
if ( p2->alive && !p1->alive )
return 1;
// check frags
if ( p1->frags > p2->frags )
return -1;
if ( p2->frags > p1->frags )
return 1;
// check deaths
if ( p1->deaths < p2->deaths )
return -1;
if ( p2->deaths < p1->deaths )
return 1;
// check index
if ( p1->index < p2->index )
return -1;
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2MPClientScoreBoardDialog::UpdatePlayerInfo()
{
m_iSectionId = 0; // 0'th row is a header
int selectedRow = -1;
int i;
CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer || !g_PR )
return;
// walk all the players and make sure they're in the scoreboard
for ( i = 1; i <= gpGlobals->maxClients; i++ )
{
bool shouldShow = g_PR->IsConnected( i );
if ( shouldShow )
{
// add the player to the list
KeyValues *playerData = new KeyValues("data");
GetPlayerScoreInfo( i, playerData );
int itemID = FindItemIDForPlayerIndex( i );
int sectionID = GetSectionFromTeamNumber( g_PR->GetTeam( i ) );
if (itemID == -1)
{
// add a new row
itemID = m_pPlayerList->AddItem( sectionID, playerData );
}
else
{
// modify the current row
m_pPlayerList->ModifyItem( itemID, sectionID, playerData );
}
if ( i == pPlayer->entindex() )
{
selectedRow = itemID; // this is the local player, hilight this row
}
// set the row color based on the players team
m_pPlayerList->SetItemFgColor( itemID, g_PR->GetTeamColor( g_PR->GetTeam( i ) ) );
playerData->deleteThis();
}
else
{
// remove the player
int itemID = FindItemIDForPlayerIndex( i );
if (itemID != -1)
{
m_pPlayerList->RemoveItem(itemID);
}
}
}
if ( selectedRow != -1 )
{
m_pPlayerList->SetSelectedItem(selectedRow);
}
}
@@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CHL2MPCLIENTSCOREBOARDDIALOG_H
#define CHL2MPCLIENTSCOREBOARDDIALOG_H
#ifdef _WIN32
#pragma once
#endif
#include <clientscoreboarddialog.h>
//-----------------------------------------------------------------------------
// Purpose: Game ScoreBoard
//-----------------------------------------------------------------------------
class CHL2MPClientScoreBoardDialog : public CClientScoreBoardDialog
{
private:
DECLARE_CLASS_SIMPLE(CHL2MPClientScoreBoardDialog, CClientScoreBoardDialog);
public:
CHL2MPClientScoreBoardDialog(IViewPort *pViewPort);
~CHL2MPClientScoreBoardDialog();
protected:
// scoreboard overrides
virtual void InitScoreboardSections();
virtual void UpdateTeamInfo();
virtual bool GetPlayerScoreInfo(int playerIndex, KeyValues *outPlayerInfo);
virtual void UpdatePlayerInfo();
// vgui overrides for rounded corner background
virtual void PaintBackground();
virtual void PaintBorder();
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
private:
virtual void AddHeader(); // add the start header of the scoreboard
virtual void AddSection(int teamType, int teamNumber); // add a new section header for a team
int GetSectionFromTeamNumber( int teamNumber );
enum
{
CSTRIKE_NAME_WIDTH = 320,
CSTRIKE_CLASS_WIDTH = 56,
CSTRIKE_SCORE_WIDTH = 40,
CSTRIKE_DEATH_WIDTH = 46,
CSTRIKE_PING_WIDTH = 46,
// CSTRIKE_VOICE_WIDTH = 40,
// CSTRIKE_FRIENDS_WIDTH = 24,
};
// rounded corners
Color m_bgColor;
Color m_borderColor;
};
#endif // CHL2MPCLIENTSCOREBOARDDIALOG_H
+174
View File
@@ -0,0 +1,174 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl2mptextwindow.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
//-----------------------------------------------------------------------------
CHL2MPTextWindow::CHL2MPTextWindow(IViewPort *pViewPort) : CTextWindow( pViewPort )
{
SetProportional( true );
m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
CreateBackground( this );
m_backgroundLayoutFinished = false;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CHL2MPTextWindow::~CHL2MPTextWindow()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2MPTextWindow::Update()
{
BaseClass::Update();
m_pOK->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2MPTextWindow::SetVisible(bool state)
{
BaseClass::SetVisible(state);
if ( state )
{
m_pOK->RequestFocus();
}
}
//-----------------------------------------------------------------------------
// Purpose: shows the text window
//-----------------------------------------------------------------------------
void CHL2MPTextWindow::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 CHL2MPTextWindow::OnKeyCodePressed(KeyCode code)
{
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 CHL2MPTextWindow::PaintBackground()
{
}
//-----------------------------------------------------------------------------
// Purpose: Scale / center the window
//-----------------------------------------------------------------------------
void CHL2MPTextWindow::PerformLayout()
{
BaseClass::PerformLayout();
// stretch the window to fullscreen
if ( !m_backgroundLayoutFinished )
LayoutBackgroundPanel( this );
m_backgroundLayoutFinished = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL2MPTextWindow::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
ApplyBackgroundSchemeSettings( this, pScheme );
}
CHL2MPSpectatorGUI::CHL2MPSpectatorGUI(IViewPort *pViewPort) : CSpectatorGUI(pViewPort)
{
}
bool CHL2MPSpectatorGUI::NeedsUpdate( void )
{
if ( !C_BasePlayer::GetLocalPlayer() )
return false;
if ( m_nLastSpecMode != C_BasePlayer::GetLocalPlayer()->GetObserverMode() )
return true;
if ( m_nLastSpecTarget != C_BasePlayer::GetLocalPlayer()->GetObserverTarget() )
return true;
return BaseClass::NeedsUpdate();
}
void CHL2MPSpectatorGUI::Update()
{
BaseClass::Update();
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if( pLocalPlayer )
{
m_nLastSpecMode = pLocalPlayer->GetObserverMode();
m_nLastSpecTarget = pLocalPlayer->GetObserverTarget();
}
}
+67
View File
@@ -0,0 +1,67 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CSTEXTWINDOW_H
#define CSTEXTWINDOW_H
#ifdef _WIN32
#pragma once
#endif
#include "vguitextwindow.h"
#include <spectatorgui.h>
//-----------------------------------------------------------------------------
// Purpose: displays the MOTD
//-----------------------------------------------------------------------------
class CHL2MPTextWindow : public CTextWindow
{
private:
DECLARE_CLASS_SIMPLE( CHL2MPTextWindow, CTextWindow );
public:
CHL2MPTextWindow(IViewPort *pViewPort);
virtual ~CHL2MPTextWindow();
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 ---------------------------------------------------
};
class CHL2MPSpectatorGUI : public CSpectatorGUI
{
private:
DECLARE_CLASS_SIMPLE( CHL2MPSpectatorGUI, CSpectatorGUI );
public:
CHL2MPSpectatorGUI( IViewPort *pViewPort );
virtual void Update( void );
virtual bool NeedsUpdate( void );
protected:
int m_nLastSpecMode;
CBaseEntity *m_nLastSpecTarget;
};
#endif // CSTEXTWINDOW_H