1070 lines
26 KiB
C++
1070 lines
26 KiB
C++
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
//
|
||
|
// Message.cpp
|
||
|
//
|
||
|
// implementation of CHudMessage class
|
||
|
//
|
||
|
#include "cbase.h"
|
||
|
#include "hudelement.h"
|
||
|
#include "hud_macros.h"
|
||
|
#include "itextmessage.h"
|
||
|
#include "iclientmode.h"
|
||
|
#include "vgui_controls/Controls.h"
|
||
|
#include "vgui_controls/Panel.h"
|
||
|
#include "vgui/ILocalize.h"
|
||
|
#include "vgui/IScheme.h"
|
||
|
#include "vgui/ISurface.h"
|
||
|
#include "client_textmessage.h"
|
||
|
#include "VGuiMatSurface/IMatSystemSurface.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
#include <ctype.h>
|
||
|
|
||
|
using namespace vgui;
|
||
|
|
||
|
#define NETWORK_MESSAGE1 "__NETMESSAGE__1"
|
||
|
#define NETWORK_MESSAGE2 "__NETMESSAGE__2"
|
||
|
#define NETWORK_MESSAGE3 "__NETMESSAGE__3"
|
||
|
#define NETWORK_MESSAGE4 "__NETMESSAGE__4"
|
||
|
#define NETWORK_MESSAGE5 "__NETMESSAGE__5"
|
||
|
#define NETWORK_MESSAGE6 "__NETMESSAGE__6"
|
||
|
#define MAX_NETMESSAGE 6
|
||
|
|
||
|
// Simultaneous message limit
|
||
|
#define MAX_TEXTMESSAGE_CHARS 2048
|
||
|
|
||
|
static const char *s_NetworkMessageNames[MAX_NETMESSAGE] = { NETWORK_MESSAGE1, NETWORK_MESSAGE2, NETWORK_MESSAGE3, NETWORK_MESSAGE4, NETWORK_MESSAGE5, NETWORK_MESSAGE6 };
|
||
|
|
||
|
const int maxHUDMessages = 16;
|
||
|
struct message_parms_t
|
||
|
{
|
||
|
client_textmessage_t *pMessage;
|
||
|
float time;
|
||
|
int x, y;
|
||
|
int totalWidth, totalHeight;
|
||
|
int width;
|
||
|
int lines;
|
||
|
int lineLength;
|
||
|
int length;
|
||
|
int r, g, b;
|
||
|
int text;
|
||
|
int fadeBlend;
|
||
|
float charTime;
|
||
|
float fadeTime;
|
||
|
const char *vguiFontName;
|
||
|
vgui::HFont font;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
//-----------------------------------------------------
|
||
|
//
|
||
|
|
||
|
class CHudMessage: public CHudElement, public vgui::Panel, public ITextMessage
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CHudMessage, vgui::Panel );
|
||
|
public:
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
TYPE_UNKNOWN = 0,
|
||
|
TYPE_POSITION,
|
||
|
TYPE_CHARACTER,
|
||
|
TYPE_FONT,
|
||
|
};
|
||
|
|
||
|
struct message_t
|
||
|
{
|
||
|
vgui::HFont font;
|
||
|
short x, y;
|
||
|
wchar_t ch;
|
||
|
byte type;
|
||
|
byte r, g, b, a;
|
||
|
};
|
||
|
|
||
|
CHudMessage( const char *pElementName );
|
||
|
~CHudMessage();
|
||
|
|
||
|
void Init( void );
|
||
|
void VidInit( void );
|
||
|
bool ShouldDraw( void );
|
||
|
virtual void Paint();
|
||
|
void MsgFunc_HudText(bf_read &msg);
|
||
|
void MsgFunc_GameTitle(bf_read &msg);
|
||
|
void MsgFunc_HudMsg(bf_read &msg);
|
||
|
|
||
|
float FadeBlend( float fadein, float fadeout, float hold, float localTime );
|
||
|
int XPosition( float x, int width, int lineWidth );
|
||
|
int YPosition( float y, int height );
|
||
|
|
||
|
void MessageAdd( const char *pName );
|
||
|
void MessageDrawScan( client_textmessage_t *pMessage, float time );
|
||
|
void MessageScanStart( void );
|
||
|
void MessageScanNextChar( void );
|
||
|
void Reset( void );
|
||
|
|
||
|
virtual void ApplySchemeSettings( IScheme *scheme );
|
||
|
|
||
|
void SetFont( HScheme scheme, const char *pFontName );
|
||
|
|
||
|
public: // ITextMessage
|
||
|
virtual void SetPosition( int x, int y );
|
||
|
virtual void AddChar( int r, int g, int b, int a, wchar_t ch );
|
||
|
|
||
|
virtual void GetLength( int *wide, int *tall, const char *string );
|
||
|
virtual int GetFontInfo( FONTABC *pABCs, vgui::HFont hFont );
|
||
|
|
||
|
virtual void SetFont( vgui::HFont hCustomFont );
|
||
|
virtual void SetDefaultFont( void );
|
||
|
|
||
|
private:
|
||
|
|
||
|
message_t *AllocMessage( void );
|
||
|
void ResetCharacters( void );
|
||
|
void PaintCharacters();
|
||
|
virtual void GetTextExtents( int *wide, int *tall, const char *string );
|
||
|
|
||
|
|
||
|
client_textmessage_t *m_pMessages[maxHUDMessages];
|
||
|
float m_startTime[maxHUDMessages];
|
||
|
message_parms_t m_parms;
|
||
|
float m_gameTitleTime;
|
||
|
client_textmessage_t *m_pGameTitle;
|
||
|
bool m_bHaveMessage;
|
||
|
|
||
|
CHudTexture *m_iconTitleLife;
|
||
|
CHudTexture *m_iconTitleHalf;
|
||
|
|
||
|
vgui::HFont m_hFont;
|
||
|
vgui::HFont m_hDefaultFont;
|
||
|
CUtlVector< message_t > m_Messages;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void DispatchHudText( const char *pszText )
|
||
|
{
|
||
|
CHudMessage *pHudMessage = (CHudMessage *)GET_HUDELEMENT( CHudMessage );
|
||
|
if ( pHudMessage )
|
||
|
{
|
||
|
if ( pszText == NULL )
|
||
|
{
|
||
|
pHudMessage->Reset();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pHudMessage->MessageAdd( pszText );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//-----------------------------------------------------
|
||
|
//
|
||
|
|
||
|
DECLARE_HUDELEMENT( CHudMessage );
|
||
|
DECLARE_HUD_MESSAGE( CHudMessage, HudText );
|
||
|
DECLARE_HUD_MESSAGE( CHudMessage, GameTitle );
|
||
|
DECLARE_HUD_MESSAGE( CHudMessage, HudMsg );
|
||
|
|
||
|
ITextMessage *textmessage = NULL;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CHudMessage::CHudMessage( const char *pElementName ) :
|
||
|
CHudElement( pElementName ), BaseClass( NULL, "HudMessage" )
|
||
|
{
|
||
|
vgui::Panel *pParent = g_pClientMode->GetViewport();
|
||
|
SetParent( pParent );
|
||
|
textmessage = this;
|
||
|
m_hFont = g_hFontTrebuchet24;
|
||
|
m_hDefaultFont = m_hFont;
|
||
|
// Clear memory out
|
||
|
ResetCharacters();
|
||
|
}
|
||
|
|
||
|
CHudMessage::~CHudMessage()
|
||
|
{
|
||
|
textmessage = NULL;
|
||
|
}
|
||
|
|
||
|
void CHudMessage::ApplySchemeSettings( IScheme *scheme )
|
||
|
{
|
||
|
BaseClass::ApplySchemeSettings( scheme );
|
||
|
|
||
|
SetPaintBackgroundEnabled( false );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::Init(void)
|
||
|
{
|
||
|
HOOK_HUD_MESSAGE( CHudMessage, HudText );
|
||
|
HOOK_HUD_MESSAGE( CHudMessage, GameTitle );
|
||
|
HOOK_HUD_MESSAGE( CHudMessage, HudMsg );
|
||
|
|
||
|
Reset();
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::VidInit( void )
|
||
|
{
|
||
|
m_iconTitleHalf = gHUD.GetIcon( "title_half" );
|
||
|
m_iconTitleLife = gHUD.GetIcon( "title_life" );
|
||
|
};
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::Reset( void )
|
||
|
{
|
||
|
memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages );
|
||
|
memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages );
|
||
|
|
||
|
m_gameTitleTime = 0;
|
||
|
m_pGameTitle = NULL;
|
||
|
m_bHaveMessage = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime )
|
||
|
{
|
||
|
float fadeTime = fadein + hold;
|
||
|
float fadeBlend;
|
||
|
|
||
|
if ( localTime < 0 )
|
||
|
return 0;
|
||
|
|
||
|
if ( localTime < fadein )
|
||
|
{
|
||
|
fadeBlend = 1 - ((fadein - localTime) / fadein);
|
||
|
}
|
||
|
else if ( localTime > fadeTime )
|
||
|
{
|
||
|
if ( fadeout > 0 )
|
||
|
fadeBlend = 1 - ((localTime - fadeTime) / fadeout);
|
||
|
else
|
||
|
fadeBlend = 0;
|
||
|
}
|
||
|
else
|
||
|
fadeBlend = 1;
|
||
|
|
||
|
return fadeBlend;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CHudMessage::XPosition( float x, int width, int totalWidth )
|
||
|
{
|
||
|
int xPos;
|
||
|
|
||
|
if ( x == -1 )
|
||
|
{
|
||
|
xPos = (ScreenWidth() - width) / 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( x < 0 )
|
||
|
xPos = (1.0 + x) * ScreenWidth() - totalWidth; // Align to right
|
||
|
else
|
||
|
xPos = x * ScreenWidth();
|
||
|
}
|
||
|
|
||
|
if ( xPos + width > ScreenWidth() )
|
||
|
xPos = ScreenWidth() - width;
|
||
|
else if ( xPos < 0 )
|
||
|
xPos = 0;
|
||
|
|
||
|
return xPos;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CHudMessage::YPosition( float y, int height )
|
||
|
{
|
||
|
int yPos;
|
||
|
|
||
|
if ( y == -1 ) // Centered?
|
||
|
yPos = (ScreenHeight() - height) * 0.5;
|
||
|
else
|
||
|
{
|
||
|
// Alight bottom?
|
||
|
if ( y < 0 )
|
||
|
yPos = (1.0 + y) * ScreenHeight() - height; // Alight bottom
|
||
|
else // align top
|
||
|
yPos = y * ScreenHeight();
|
||
|
}
|
||
|
|
||
|
if ( yPos + height > ScreenHeight() )
|
||
|
yPos = ScreenHeight() - height;
|
||
|
else if ( yPos < 0 )
|
||
|
yPos = 0;
|
||
|
|
||
|
return yPos;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MessageScanNextChar( void )
|
||
|
{
|
||
|
int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue;
|
||
|
int blend;
|
||
|
|
||
|
srcRed = m_parms.pMessage->r1;
|
||
|
srcGreen = m_parms.pMessage->g1;
|
||
|
srcBlue = m_parms.pMessage->b1;
|
||
|
blend = 0; // Pure source
|
||
|
|
||
|
destRed = destGreen = destBlue = 0;
|
||
|
|
||
|
switch( m_parms.pMessage->effect )
|
||
|
{
|
||
|
// Fade-in / Fade-out
|
||
|
case 0:
|
||
|
case 1:
|
||
|
destRed = destGreen = destBlue = 0;
|
||
|
blend = m_parms.fadeBlend;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
m_parms.charTime += m_parms.pMessage->fadein;
|
||
|
if ( m_parms.charTime > m_parms.time )
|
||
|
{
|
||
|
srcRed = srcGreen = srcBlue = 0;
|
||
|
blend = 0; // pure source
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float deltaTime = m_parms.time - m_parms.charTime;
|
||
|
|
||
|
destRed = destGreen = destBlue = 0;
|
||
|
if ( m_parms.time > m_parms.fadeTime )
|
||
|
{
|
||
|
blend = m_parms.fadeBlend;
|
||
|
}
|
||
|
else if ( deltaTime > m_parms.pMessage->fxtime )
|
||
|
blend = 0; // pure dest
|
||
|
else
|
||
|
{
|
||
|
destRed = m_parms.pMessage->r2;
|
||
|
destGreen = m_parms.pMessage->g2;
|
||
|
destBlue = m_parms.pMessage->b2;
|
||
|
blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if ( blend > 255 )
|
||
|
blend = 255;
|
||
|
else if ( blend < 0 )
|
||
|
blend = 0;
|
||
|
|
||
|
m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8;
|
||
|
m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8;
|
||
|
m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8;
|
||
|
|
||
|
#if 0
|
||
|
if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 )
|
||
|
{
|
||
|
textmessage->AddChar( m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2, 255, m_parms.text );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void CHudMessage::SetFont( HScheme scheme, const char *pFontName )
|
||
|
{
|
||
|
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( scheme );
|
||
|
|
||
|
if ( pScheme )
|
||
|
{
|
||
|
vgui::HFont font = pScheme->GetFont( pFontName );
|
||
|
textmessage->SetFont( font );
|
||
|
m_parms.font = font;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MessageScanStart( void )
|
||
|
{
|
||
|
switch( m_parms.pMessage->effect )
|
||
|
{
|
||
|
// Fade-in / out with flicker
|
||
|
case 1:
|
||
|
case 0:
|
||
|
m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime;
|
||
|
|
||
|
|
||
|
if ( m_parms.time < m_parms.pMessage->fadein )
|
||
|
{
|
||
|
m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255);
|
||
|
}
|
||
|
else if ( m_parms.time > m_parms.fadeTime )
|
||
|
{
|
||
|
if ( m_parms.pMessage->fadeout > 0 )
|
||
|
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
|
||
|
else
|
||
|
m_parms.fadeBlend = 255; // Pure dest (off)
|
||
|
}
|
||
|
else
|
||
|
m_parms.fadeBlend = 0; // Pure source (on)
|
||
|
m_parms.charTime = 0;
|
||
|
|
||
|
if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 )
|
||
|
m_parms.charTime = 1;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime;
|
||
|
|
||
|
if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 )
|
||
|
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
|
||
|
else
|
||
|
m_parms.fadeBlend = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
m_parms.font = g_hFontTrebuchet24;
|
||
|
|
||
|
if ( m_parms.vguiFontName != NULL &&
|
||
|
m_parms.vguiFontName[ 0 ] )
|
||
|
{
|
||
|
|
||
|
SetFont( vgui::scheme()->GetDefaultScheme(), m_parms.vguiFontName );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time )
|
||
|
{
|
||
|
int i, j, length, width;
|
||
|
const wchar_t *pText;
|
||
|
wchar_t textBuf[ 1024 ];
|
||
|
|
||
|
{
|
||
|
// look up in localization table
|
||
|
// strip off any trailing newlines
|
||
|
int len = Q_strlen( pMessage->pMessage );
|
||
|
int tempLen = len + 2;
|
||
|
char *localString = (char *)_alloca( tempLen );
|
||
|
Q_strncpy( localString, pMessage->pMessage, tempLen );
|
||
|
if (V_iscntrl(localString[len - 1]))
|
||
|
{
|
||
|
localString[len - 1] = 0;
|
||
|
}
|
||
|
|
||
|
pText = g_pVGuiLocalize->Find( localString );
|
||
|
if ( !pText )
|
||
|
{
|
||
|
g_pVGuiLocalize->ConvertANSIToUnicode( pMessage->pMessage, textBuf, sizeof( textBuf ) );
|
||
|
pText = textBuf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const wchar_t *pPerm = pText;
|
||
|
|
||
|
// Count lines
|
||
|
m_parms.lines = 1;
|
||
|
m_parms.time = time;
|
||
|
m_parms.pMessage = pMessage;
|
||
|
length = 0;
|
||
|
width = 0;
|
||
|
m_parms.totalWidth = 0;
|
||
|
m_parms.vguiFontName = pMessage->pVGuiSchemeFontName;
|
||
|
|
||
|
m_parms.font = g_hFontTrebuchet24;
|
||
|
|
||
|
while ( *pText )
|
||
|
{
|
||
|
if ( *pText == '\n' )
|
||
|
{
|
||
|
m_parms.lines++;
|
||
|
if ( width > m_parms.totalWidth )
|
||
|
m_parms.totalWidth = width;
|
||
|
width = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
width += vgui::surface()->GetCharacterWidth( m_parms.font, *pText );
|
||
|
}
|
||
|
pText++;
|
||
|
length++;
|
||
|
}
|
||
|
if ( width > m_parms.totalWidth )
|
||
|
m_parms.totalWidth = width;
|
||
|
m_parms.length = length;
|
||
|
|
||
|
int fontHeight = vgui::surface()->GetFontTall( m_parms.font );
|
||
|
|
||
|
m_parms.totalHeight = ( m_parms.lines * fontHeight );
|
||
|
|
||
|
m_parms.y = YPosition( pMessage->y, m_parms.totalHeight );
|
||
|
pText = pPerm;
|
||
|
|
||
|
m_parms.charTime = 0;
|
||
|
|
||
|
float flBoxPixels = 0.0f;
|
||
|
|
||
|
MessageScanStart();
|
||
|
|
||
|
if ( pMessage->bRoundedRectBackdropBox )
|
||
|
{
|
||
|
// 2.0f since we have extra space at both the top and bottom
|
||
|
flBoxPixels = pMessage->flBoxSize * fontHeight;
|
||
|
|
||
|
// Draw the box
|
||
|
int boxx = XPosition( pMessage->x, m_parms.totalWidth, m_parms.totalWidth );
|
||
|
int boxy = YPosition( pMessage->y, m_parms.totalHeight );
|
||
|
|
||
|
boxx -= flBoxPixels;
|
||
|
boxy -= flBoxPixels * 0.5f;
|
||
|
|
||
|
float flAlphaScale = clamp( ( 255.0f - (float)m_parms.fadeBlend ) / 255.0f, 0.0f, 1.0f );
|
||
|
Color boxColor(
|
||
|
pMessage->boxcolor[ 0 ],
|
||
|
pMessage->boxcolor[ 1 ],
|
||
|
pMessage->boxcolor[ 2 ],
|
||
|
pMessage->boxcolor[ 3 ] * flAlphaScale );
|
||
|
|
||
|
DrawBox( boxx, boxy, m_parms.totalWidth + 2.0f * flBoxPixels, m_parms.totalHeight + 2.0f * flBoxPixels * 0.5f, boxColor, 1.0f );
|
||
|
}
|
||
|
|
||
|
wchar_t line[ 512 ];
|
||
|
for ( i = 0; i < m_parms.lines; i++ )
|
||
|
{
|
||
|
m_parms.lineLength = 0;
|
||
|
m_parms.width = 0;
|
||
|
while ( *pText && *pText != '\n' )
|
||
|
{
|
||
|
wchar_t c = *pText;
|
||
|
line[m_parms.lineLength] = c;
|
||
|
m_parms.width += vgui::surface()->GetCharacterWidth( m_parms.font, c);
|
||
|
m_parms.lineLength++;
|
||
|
if ( m_parms.lineLength > (ARRAYSIZE(line)-1) )
|
||
|
{
|
||
|
m_parms.lineLength = ARRAYSIZE(line)-1;
|
||
|
}
|
||
|
pText++;
|
||
|
}
|
||
|
pText++; // Skip LF
|
||
|
line[m_parms.lineLength] = 0;
|
||
|
|
||
|
m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth );
|
||
|
|
||
|
textmessage->SetPosition( m_parms.x, m_parms.y );
|
||
|
|
||
|
if (m_parms.fadeBlend > 255)
|
||
|
m_parms.fadeBlend = 255;
|
||
|
|
||
|
for ( j = 0; j < m_parms.lineLength; j++ )
|
||
|
{
|
||
|
m_parms.text = line[j];
|
||
|
MessageScanNextChar();
|
||
|
textmessage->AddChar( m_parms.r, m_parms.g, m_parms.b, 255 - m_parms.fadeBlend, m_parms.text );
|
||
|
}
|
||
|
|
||
|
m_parms.y += vgui::surface()->GetFontTall( m_parms.font );
|
||
|
}
|
||
|
|
||
|
// Restore default font
|
||
|
textmessage->SetDefaultFont();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CHudMessage::ShouldDraw( void )
|
||
|
{
|
||
|
return ( CHudElement::ShouldDraw() &&
|
||
|
( m_bHaveMessage || m_Messages.Count() ) );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::Paint()
|
||
|
{
|
||
|
int i, drawn;
|
||
|
client_textmessage_t *pMessage;
|
||
|
float endTime;
|
||
|
|
||
|
drawn = 0;
|
||
|
|
||
|
if ( m_gameTitleTime > 0 )
|
||
|
{
|
||
|
float localTime = gpGlobals->curtime - m_gameTitleTime;
|
||
|
float brightness;
|
||
|
|
||
|
// Maybe timer isn't set yet
|
||
|
if ( m_gameTitleTime > gpGlobals->curtime )
|
||
|
{
|
||
|
m_gameTitleTime = gpGlobals->curtime;
|
||
|
}
|
||
|
|
||
|
if ( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) )
|
||
|
{
|
||
|
m_gameTitleTime = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime );
|
||
|
|
||
|
int halfWidth = m_iconTitleHalf->Width();
|
||
|
int fullWidth = halfWidth + m_iconTitleLife->Width();
|
||
|
int fullHeight = m_iconTitleHalf->Height();
|
||
|
|
||
|
int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth );
|
||
|
int y = YPosition( m_pGameTitle->y, fullHeight );
|
||
|
|
||
|
m_iconTitleHalf->DrawSelf( x, y, Color( m_pGameTitle->r1, m_pGameTitle->g1, m_pGameTitle->b1, brightness * 255 ) );
|
||
|
m_iconTitleLife->DrawSelf( x + halfWidth, y, Color( m_pGameTitle->r1, m_pGameTitle->g1, m_pGameTitle->b1, brightness * 255 ) );
|
||
|
drawn = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fixup level transitions
|
||
|
for ( i = 0; i < maxHUDMessages; i++ )
|
||
|
{
|
||
|
// Assume m_parms.time contains last time
|
||
|
if ( m_pMessages[i] )
|
||
|
{
|
||
|
pMessage = m_pMessages[i];
|
||
|
if ( m_startTime[i] > gpGlobals->curtime )
|
||
|
m_startTime[i] = gpGlobals->curtime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( i = 0; i < maxHUDMessages; i++ )
|
||
|
{
|
||
|
if ( m_pMessages[i] )
|
||
|
{
|
||
|
pMessage = m_pMessages[i];
|
||
|
|
||
|
// This is when the message is over
|
||
|
switch( pMessage->effect )
|
||
|
{
|
||
|
case 0:
|
||
|
case 1:
|
||
|
endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime;
|
||
|
break;
|
||
|
|
||
|
// Fade in is per character in scanning messages
|
||
|
case 2:
|
||
|
endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
endTime = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( gpGlobals->curtime <= endTime )
|
||
|
{
|
||
|
float messageTime = gpGlobals->curtime - m_startTime[i];
|
||
|
|
||
|
// Draw the message
|
||
|
// effect 0 is fade in/fade out
|
||
|
// effect 1 is flickery credits
|
||
|
// effect 2 is write out (training room)
|
||
|
MessageDrawScan( pMessage, messageTime );
|
||
|
|
||
|
drawn++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The message is over
|
||
|
m_pMessages[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remember the time -- to fix up level transitions
|
||
|
m_parms.time = gpGlobals->curtime;
|
||
|
|
||
|
// Did we draw any messages?
|
||
|
if ( !drawn )
|
||
|
{
|
||
|
m_bHaveMessage = false;
|
||
|
}
|
||
|
|
||
|
PaintCharacters();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MessageAdd( const char *pName )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
float time = gpGlobals->curtime;
|
||
|
|
||
|
client_textmessage_t *pMessage = NULL;
|
||
|
|
||
|
if ( pName[0] == '#' )
|
||
|
{
|
||
|
pMessage = TextMessageGet( pName+1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMessage = TextMessageGet( pName );
|
||
|
}
|
||
|
|
||
|
if ( !pMessage )
|
||
|
return;
|
||
|
|
||
|
if ( pMessage->pClearMessage )
|
||
|
{
|
||
|
for ( i = 0; i < maxHUDMessages; i++ )
|
||
|
{
|
||
|
if ( m_pMessages[ i ] && !Q_stricmp( m_pMessages[ i ]->pName, pMessage->pClearMessage ) )
|
||
|
{
|
||
|
m_startTime[ i ] = 0.0f;
|
||
|
m_pMessages[ i ] = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( i = 0; i < maxHUDMessages; i++ )
|
||
|
{
|
||
|
if ( !m_pMessages[i] )
|
||
|
{
|
||
|
m_pMessages[i] = pMessage;
|
||
|
m_startTime[i] = time;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remember the time -- to fix up level transitions
|
||
|
m_parms.time = time;
|
||
|
|
||
|
m_bHaveMessage = true;
|
||
|
// Force this now so that SCR_UpdateScreen will paint the panel immediately!!!
|
||
|
SetVisible( true );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MsgFunc_HudText( bf_read &msg )
|
||
|
{
|
||
|
char szString[2048];
|
||
|
msg.ReadString( szString, sizeof(szString) );
|
||
|
|
||
|
MessageAdd( szString );
|
||
|
}
|
||
|
|
||
|
#include "ivieweffects.h"
|
||
|
#include "shake.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::MsgFunc_GameTitle( bf_read &msg )
|
||
|
{
|
||
|
m_pGameTitle = TextMessageGet( "GAMETITLE" );
|
||
|
if ( m_pGameTitle != NULL )
|
||
|
{
|
||
|
m_gameTitleTime = gpGlobals->curtime;
|
||
|
|
||
|
m_bHaveMessage = true;
|
||
|
}
|
||
|
|
||
|
// if ( READ_BYTE() )
|
||
|
{
|
||
|
ScreenFade_t sf;
|
||
|
memset( &sf, 0, sizeof( sf ) );
|
||
|
sf.a = 255;
|
||
|
sf.r = 0;
|
||
|
sf.g = 0;
|
||
|
sf.b = 0;
|
||
|
sf.duration = (float)(1<<SCREENFADE_FRACBITS) * 5.0f;
|
||
|
sf.holdTime = (float)(1<<SCREENFADE_FRACBITS) * 1.0f;
|
||
|
sf.fadeFlags = FFADE_IN | FFADE_PURGE;
|
||
|
vieweffects->Fade( sf );
|
||
|
|
||
|
Msg( "%i gametitle fade\n", gpGlobals->framecount );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CHudMessage::MsgFunc_HudMsg(bf_read &msg)
|
||
|
{
|
||
|
// Position command $position x y
|
||
|
// x & y are from 0 to 1 to be screen resolution independent
|
||
|
// -1 means center in each dimension
|
||
|
// Effect command $effect <effect number>
|
||
|
// effect 0 is fade in/fade out
|
||
|
// effect 1 is flickery credits
|
||
|
// effect 2 is write out (training room)
|
||
|
// Text color r g b command $color
|
||
|
// Text color r g b command $color2
|
||
|
// fadein time fadeout time / hold time
|
||
|
// $fadein (message fade in time - per character in effect 2)
|
||
|
// $fadeout (message fade out time)
|
||
|
// $holdtime (stay on the screen for this long)
|
||
|
|
||
|
int channel = msg.ReadByte() % MAX_NETMESSAGE; // Pick the buffer
|
||
|
|
||
|
client_textmessage_t *pNetMessage = TextMessageGet( s_NetworkMessageNames[ channel ] );
|
||
|
|
||
|
if ( !pNetMessage || !pNetMessage->pMessage )
|
||
|
return;
|
||
|
|
||
|
pNetMessage->x = msg.ReadFloat();
|
||
|
pNetMessage->y = msg.ReadFloat();
|
||
|
|
||
|
pNetMessage->r1 = msg.ReadByte();
|
||
|
pNetMessage->g1 = msg.ReadByte();
|
||
|
pNetMessage->b1 = msg.ReadByte();
|
||
|
pNetMessage->a1 = msg.ReadByte();
|
||
|
|
||
|
pNetMessage->r2 = msg.ReadByte();
|
||
|
pNetMessage->g2 = msg.ReadByte();
|
||
|
pNetMessage->b2 = msg.ReadByte();
|
||
|
pNetMessage->a2 = msg.ReadByte();
|
||
|
|
||
|
pNetMessage->effect = msg.ReadByte();
|
||
|
|
||
|
pNetMessage->fadein = msg.ReadFloat();
|
||
|
pNetMessage->fadeout = msg.ReadFloat();
|
||
|
pNetMessage->holdtime = msg.ReadFloat();
|
||
|
pNetMessage->fxtime = msg.ReadFloat();
|
||
|
|
||
|
pNetMessage->pName = s_NetworkMessageNames[ channel ];
|
||
|
|
||
|
// see tmessage.cpp why 512
|
||
|
msg.ReadString( (char*)pNetMessage->pMessage, 512 );
|
||
|
|
||
|
MessageAdd( pNetMessage->pName );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Get font sizes
|
||
|
// Input : *pWidth -
|
||
|
// Output : int
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CHudMessage::GetFontInfo( FONTABC *pABCs, vgui::HFont hFont )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if ( !hFont )
|
||
|
{
|
||
|
hFont = m_hFont;
|
||
|
}
|
||
|
|
||
|
if ( !hFont )
|
||
|
return 0;
|
||
|
|
||
|
if ( pABCs )
|
||
|
{
|
||
|
for ( i =0; i < 256; i++ )
|
||
|
{
|
||
|
int a, b, c;
|
||
|
vgui::surface()->GetCharABCwide( hFont, (char)i, a, b, c );
|
||
|
pABCs[i].abcA = a;
|
||
|
pABCs[i].abcB = b;
|
||
|
pABCs[i].abcC = c;
|
||
|
pABCs[i].total = a+b+c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return vgui::surface()->GetFontTall( hFont );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Clear all messages out of active list, etc.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::ResetCharacters( void )
|
||
|
{
|
||
|
m_Messages.Purge();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Grab next free message, if any
|
||
|
// Output : CTextMessagePanel::message_t
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CHudMessage::message_t *CHudMessage::AllocMessage( void )
|
||
|
{
|
||
|
message_t *msg;
|
||
|
|
||
|
if ( m_Messages.Count() >= MAX_TEXTMESSAGE_CHARS )
|
||
|
return NULL;
|
||
|
|
||
|
msg = &m_Messages[ m_Messages.AddToTail() ];
|
||
|
|
||
|
msg->type = TYPE_UNKNOWN;
|
||
|
msg->x = 0;
|
||
|
msg->y = 0;
|
||
|
msg->ch = 0;
|
||
|
msg->r = 0;
|
||
|
msg->g = 0;
|
||
|
msg->b = 0;
|
||
|
msg->a = 0;
|
||
|
msg->font = 0;
|
||
|
|
||
|
SetVisible( true );
|
||
|
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : x -
|
||
|
// y -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::SetPosition( int x, int y )
|
||
|
{
|
||
|
message_t *msg = AllocMessage();
|
||
|
if ( !msg )
|
||
|
return;
|
||
|
|
||
|
msg->type = TYPE_POSITION;
|
||
|
|
||
|
// Used fields
|
||
|
msg->x = x;
|
||
|
msg->y = y;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Adds a character to the active list, if possible
|
||
|
// Input : x -
|
||
|
// y -
|
||
|
// r -
|
||
|
// g -
|
||
|
// b -
|
||
|
// a -
|
||
|
// ch -
|
||
|
// Output : int
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::AddChar( int r, int g, int b, int a, wchar_t ch )
|
||
|
{
|
||
|
message_t *msg = AllocMessage();
|
||
|
if ( !msg )
|
||
|
return;
|
||
|
|
||
|
msg->type = TYPE_CHARACTER;
|
||
|
|
||
|
// Used fields
|
||
|
msg->r = r;
|
||
|
msg->g = g;
|
||
|
msg->b = b;
|
||
|
msg->a = a;
|
||
|
msg->ch = ch;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Determine width and height of specified string
|
||
|
// Input : *wide -
|
||
|
// *tall -
|
||
|
// *string -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::GetTextExtents( int *wide, int *tall, const char *string )
|
||
|
{
|
||
|
*wide = g_pMatSystemSurface->DrawTextLen( m_hFont, "%s", (char *)string );
|
||
|
*tall = vgui::surface()->GetFontTall( m_hFont );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::SetFont( vgui::HFont hCustomFont )
|
||
|
{
|
||
|
m_hFont = hCustomFont;
|
||
|
|
||
|
message_t *msg = AllocMessage();
|
||
|
if ( !msg )
|
||
|
return;
|
||
|
|
||
|
msg->type = TYPE_FONT;
|
||
|
|
||
|
// Used fields
|
||
|
msg->font = m_hFont;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::SetDefaultFont( void )
|
||
|
{
|
||
|
SetFont( m_hDefaultFont );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Draw current text items
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CHudMessage::PaintCharacters()
|
||
|
{
|
||
|
int xpos = 0, ypos = 0;
|
||
|
vgui::surface()->DrawSetTextFont( m_hFont );
|
||
|
|
||
|
int messageCount = m_Messages.Count();
|
||
|
for ( int i = 0 ; i < messageCount; ++i )
|
||
|
{
|
||
|
message_t *msg = &m_Messages[ i ];
|
||
|
|
||
|
switch ( msg->type )
|
||
|
{
|
||
|
default:
|
||
|
case TYPE_UNKNOWN:
|
||
|
Assert( 0 );
|
||
|
break;
|
||
|
case TYPE_POSITION:
|
||
|
xpos = msg->x;
|
||
|
ypos = msg->y;
|
||
|
break;
|
||
|
case TYPE_FONT:
|
||
|
m_hFont = msg->font;
|
||
|
vgui::surface()->DrawSetTextFont( m_hFont );
|
||
|
break;
|
||
|
case TYPE_CHARACTER:
|
||
|
if ( m_hFont )
|
||
|
{
|
||
|
int a, b, c;
|
||
|
vgui::surface()->GetCharABCwide( m_hFont, msg->ch, a, b, c );
|
||
|
|
||
|
if ( msg->ch > 32 )
|
||
|
{
|
||
|
vgui::surface()->DrawSetTextColor( msg->r, msg->g, msg->b, msg->a );
|
||
|
vgui::surface()->DrawSetTextPos( xpos, ypos );
|
||
|
vgui::surface()->DrawUnicodeChar( msg->ch );
|
||
|
}
|
||
|
xpos += a + b + c;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ResetCharacters();
|
||
|
}
|
||
|
|
||
|
void CHudMessage::GetLength( int *wide, int *tall, const char *string )
|
||
|
{
|
||
|
GetTextExtents( wide, tall, string );
|
||
|
}
|