You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
850 lines
21 KiB
850 lines
21 KiB
//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ============ |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
// There are hud.h's coming out of the woodwork so this ensures that we get the right one. |
|
#include "../cl_dll/hud.h" |
|
#include "../cl_dll/cl_util.h" |
|
|
|
#include <assert.h> |
|
#include <string.h> |
|
#include <stdio.h> |
|
|
|
#include "../cl_dll/parsemsg.h" |
|
#include "../cl_dll/hud_servers.h" |
|
#include "../cl_dll/demo.h" |
|
|
|
#include "demo_api.h" |
|
#include "voice_status.h" |
|
#include "r_efx.h" |
|
#include "entity_types.h" |
|
#include "VGUI_ActionSignal.h" |
|
#include "VGUI_Scheme.h" |
|
#include "VGUI_TextImage.h" |
|
#include "vgui_loadtga.h" |
|
#include "vgui_helpers.h" |
|
#include "vgui_mousecode.h" |
|
|
|
using namespace vgui; |
|
|
|
extern int cam_thirdperson; |
|
|
|
#define VOICE_MODEL_INTERVAL 0.3 |
|
#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. |
|
#define SQUELCHOSCILLATE_PER_SECOND 2.0f |
|
|
|
extern BitmapTGA *LoadTGA( const char* pImageName ); |
|
|
|
// ---------------------------------------------------------------------- // |
|
// The voice manager for the client. |
|
// ---------------------------------------------------------------------- // |
|
CVoiceStatus g_VoiceStatus; |
|
|
|
CVoiceStatus* GetClientVoiceMgr() |
|
{ |
|
return &g_VoiceStatus; |
|
} |
|
|
|
// ---------------------------------------------------------------------- // |
|
// CVoiceStatus. |
|
// ---------------------------------------------------------------------- // |
|
static CVoiceStatus *g_pInternalVoiceStatus = NULL; |
|
|
|
int __MsgFunc_VoiceMask( const char *pszName, int iSize, void *pbuf ) |
|
{ |
|
if( g_pInternalVoiceStatus ) |
|
g_pInternalVoiceStatus->HandleVoiceMaskMsg( iSize, pbuf ); |
|
|
|
return 1; |
|
} |
|
|
|
int __MsgFunc_ReqState( const char *pszName, int iSize, void *pbuf ) |
|
{ |
|
if( g_pInternalVoiceStatus ) |
|
g_pInternalVoiceStatus->HandleReqStateMsg( iSize, pbuf ); |
|
|
|
return 1; |
|
} |
|
|
|
int g_BannedPlayerPrintCount; |
|
|
|
void ForEachBannedPlayer( char id[16] ) |
|
{ |
|
char str[256]; |
|
|
|
sprintf( str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", |
|
g_BannedPlayerPrintCount++, |
|
id[0], id[1], id[2], id[3], |
|
id[4], id[5], id[6], id[7], |
|
id[8], id[9], id[10], id[11], |
|
id[12], id[13], id[14], id[15] |
|
); |
|
|
|
strupr( str ); |
|
|
|
gEngfuncs.pfnConsolePrint(str); |
|
} |
|
|
|
void ShowBannedCallback() |
|
{ |
|
if( g_pInternalVoiceStatus ) |
|
{ |
|
g_BannedPlayerPrintCount = 0; |
|
gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); |
|
g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer( ForEachBannedPlayer ); |
|
gEngfuncs.pfnConsolePrint("------------------------------\n"); |
|
} |
|
} |
|
|
|
// ---------------------------------------------------------------------- // |
|
// CVoiceStatus. |
|
// ---------------------------------------------------------------------- // |
|
CVoiceStatus::CVoiceStatus() |
|
{ |
|
m_bBanMgrInitialized = false; |
|
m_LastUpdateServerState = 0; |
|
|
|
m_pSpeakerLabelIcon = NULL; |
|
m_pScoreboardNeverSpoken = NULL; |
|
m_pScoreboardNotSpeaking = NULL; |
|
m_pScoreboardSpeaking = NULL; |
|
m_pScoreboardSpeaking2 = NULL; |
|
m_pScoreboardSquelch = NULL; |
|
m_pScoreboardBanned = NULL; |
|
|
|
m_pLocalBitmap = NULL; |
|
m_pAckBitmap = NULL; |
|
|
|
m_bTalking = m_bServerAcked = false; |
|
|
|
memset( m_pBanButtons, 0, sizeof(m_pBanButtons) ); |
|
|
|
m_bServerModEnable = -1; |
|
|
|
m_pchGameDir = NULL; |
|
} |
|
|
|
CVoiceStatus::~CVoiceStatus() |
|
{ |
|
g_pInternalVoiceStatus = NULL; |
|
|
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
{ |
|
delete m_Labels[i].m_pLabel; |
|
m_Labels[i].m_pLabel = NULL; |
|
|
|
delete m_Labels[i].m_pIcon; |
|
m_Labels[i].m_pIcon = NULL; |
|
|
|
delete m_Labels[i].m_pBackground; |
|
m_Labels[i].m_pBackground = NULL; |
|
} |
|
|
|
delete m_pLocalLabel; |
|
m_pLocalLabel = NULL; |
|
|
|
FreeBitmaps(); |
|
|
|
if( m_pchGameDir ) |
|
{ |
|
if( m_bBanMgrInitialized ) |
|
{ |
|
m_BanMgr.SaveState( m_pchGameDir ); |
|
} |
|
|
|
free( m_pchGameDir ); |
|
} |
|
} |
|
|
|
int CVoiceStatus::Init( IVoiceStatusHelper *pHelper, Panel **pParentPanel ) |
|
{ |
|
// Setup the voice_modenable cvar. |
|
gEngfuncs.pfnRegisterVariable( "voice_modenable", "1", FCVAR_ARCHIVE ); |
|
|
|
gEngfuncs.pfnRegisterVariable( "voice_clientdebug", "0", 0 ); |
|
|
|
gEngfuncs.pfnAddCommand( "voice_showbanned", ShowBannedCallback ); |
|
|
|
if( gEngfuncs.pfnGetGameDirectory() ) |
|
{ |
|
m_BanMgr.Init( gEngfuncs.pfnGetGameDirectory() ); |
|
m_bBanMgrInitialized = true; |
|
} |
|
|
|
assert( !g_pInternalVoiceStatus ); |
|
g_pInternalVoiceStatus = this; |
|
|
|
m_BlinkTimer = 0; |
|
m_VoiceHeadModel = NULL; |
|
memset( m_Labels, 0, sizeof(m_Labels) ); |
|
|
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
{ |
|
CVoiceLabel *pLabel = &m_Labels[i]; |
|
|
|
pLabel->m_pBackground = new Label( "" ); |
|
|
|
if( pLabel->m_pLabel = new Label( "" ) ) |
|
{ |
|
pLabel->m_pLabel->setVisible( true ); |
|
pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); |
|
pLabel->m_pLabel->setTextAlignment( Label::a_east ); |
|
pLabel->m_pLabel->setContentAlignment( Label::a_east ); |
|
pLabel->m_pLabel->setParent( pLabel->m_pBackground ); |
|
} |
|
|
|
if( pLabel->m_pIcon = new ImagePanel( NULL ) ) |
|
{ |
|
pLabel->m_pIcon->setVisible( true ); |
|
pLabel->m_pIcon->setParent( pLabel->m_pBackground ); |
|
} |
|
|
|
pLabel->m_clientindex = -1; |
|
} |
|
|
|
m_pLocalLabel = new ImagePanel( NULL ); |
|
|
|
m_bInSquelchMode = false; |
|
|
|
m_pHelper = pHelper; |
|
m_pParentPanel = pParentPanel; |
|
gHUD.AddHudElem( this ); |
|
m_iFlags = HUD_ACTIVE; |
|
HOOK_MESSAGE( VoiceMask ); |
|
HOOK_MESSAGE( ReqState ); |
|
|
|
// Cache the game directory for use when we shut down |
|
const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); |
|
m_pchGameDir = (char *)malloc( strlen( pchGameDirT ) + 1 ); |
|
strcpy( m_pchGameDir, pchGameDirT ); |
|
|
|
return 1; |
|
} |
|
|
|
int CVoiceStatus::VidInit() |
|
{ |
|
FreeBitmaps(); |
|
|
|
if( m_pLocalBitmap = vgui_LoadTGA( "gfx/vgui/icntlk_pl.tga" ) ) |
|
{ |
|
m_pLocalBitmap->setColor( Color( 255, 255, 255, 135 ) ); |
|
} |
|
|
|
if( m_pAckBitmap = vgui_LoadTGA( "gfx/vgui/icntlk_sv.tga" ) ) |
|
{ |
|
m_pAckBitmap->setColor( Color( 255, 255, 255, 135 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
} |
|
|
|
m_pLocalLabel->setImage( m_pLocalBitmap ); |
|
m_pLocalLabel->setVisible( false ); |
|
|
|
if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha( "gfx/vgui/speaker4.tga" ) ) |
|
m_pSpeakerLabelIcon->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha( "gfx/vgui/640_speaker1.tga" ) ) |
|
m_pScoreboardNeverSpoken->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha( "gfx/vgui/640_speaker2.tga" ) ) |
|
m_pScoreboardNotSpeaking->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha( "gfx/vgui/640_speaker3.tga" ) ) |
|
m_pScoreboardSpeaking->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha( "gfx/vgui/640_speaker4.tga" ) ) |
|
m_pScoreboardSpeaking2->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardSquelch = vgui_LoadTGA( "gfx/vgui/icntlk_squelch.tga" ) ) |
|
m_pScoreboardSquelch->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
if( m_pScoreboardBanned = vgui_LoadTGA( "gfx/vgui/640_voiceblocked.tga" ) ) |
|
m_pScoreboardBanned->setColor( Color( 255, 255, 255, 1 ) ); // Give just a tiny bit of translucency so software draws correctly. |
|
|
|
// Figure out the voice head model height. |
|
m_VoiceHeadModelHeight = 45; |
|
char *pFile = (char *)gEngfuncs.COM_LoadFile( "scripts/voicemodel.txt", 5, NULL ); |
|
if( pFile ) |
|
{ |
|
char token[4096]; |
|
|
|
gEngfuncs.COM_ParseFile( pFile, token ); |
|
if( token[0] >= '0' && token[0] <= '9' ) |
|
{ |
|
m_VoiceHeadModelHeight = (float)atof( token ); |
|
} |
|
|
|
gEngfuncs.COM_FreeFile( pFile ); |
|
} |
|
|
|
m_VoiceHeadModel = gEngfuncs.pfnSPR_Load( "sprites/voiceicon.spr" ); |
|
|
|
return TRUE; |
|
} |
|
|
|
void CVoiceStatus::Frame( double frametime ) |
|
{ |
|
// check server banned players once per second |
|
if( gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1 ) |
|
{ |
|
UpdateServerState( false ); |
|
} |
|
|
|
m_BlinkTimer += frametime; |
|
|
|
// Update speaker labels. |
|
if( m_pHelper->CanShowSpeakerLabels() ) |
|
{ |
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); |
|
} |
|
else |
|
{ |
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
m_Labels[i].m_pBackground->setVisible( false ); |
|
} |
|
|
|
for( int i = 0; i < VOICE_MAX_PLAYERS; i++ ) |
|
UpdateBanButton(i); |
|
} |
|
|
|
void CVoiceStatus::CreateEntities() |
|
{ |
|
if( !m_VoiceHeadModel ) |
|
return; |
|
|
|
cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); |
|
|
|
int iOutModel = 0; |
|
for( int i = 0; i < VOICE_MAX_PLAYERS; i++ ) |
|
{ |
|
if( !m_VoicePlayers[i] ) |
|
continue; |
|
|
|
cl_entity_s *pClient = gEngfuncs.GetEntityByIndex( i + 1 ); |
|
|
|
// Don't show an icon if the player is not in our PVS. |
|
if( !pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum ) |
|
continue; |
|
|
|
// Don't show an icon for dead or spectating players (ie: invisible entities). |
|
if( pClient->curstate.effects & EF_NODRAW ) |
|
continue; |
|
|
|
// Don't show an icon for the local player unless we're in thirdperson mode. |
|
if( pClient == localPlayer && !cam_thirdperson ) |
|
continue; |
|
|
|
cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; |
|
++iOutModel; |
|
|
|
memset( pEnt, 0, sizeof(*pEnt) ); |
|
|
|
pEnt->curstate.rendermode = kRenderTransAdd; |
|
pEnt->curstate.renderamt = 255; |
|
pEnt->baseline.renderamt = 255; |
|
pEnt->curstate.renderfx = kRenderFxNoDissipation; |
|
pEnt->curstate.framerate = 1; |
|
pEnt->curstate.frame = 0; |
|
pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer( m_VoiceHeadModel ); |
|
pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; |
|
pEnt->curstate.scale = 0.5f; |
|
|
|
pEnt->origin[0] = pEnt->origin[1] = 0; |
|
pEnt->origin[2] = 45; |
|
|
|
VectorAdd( pEnt->origin, pClient->origin, pEnt->origin ); |
|
|
|
// Tell the engine. |
|
gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, pEnt ); |
|
} |
|
} |
|
|
|
void CVoiceStatus::UpdateSpeakerStatus( int entindex, qboolean bTalking ) |
|
{ |
|
if( !*m_pParentPanel ) |
|
return; |
|
|
|
if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) |
|
{ |
|
char msg[256]; |
|
|
|
sprintf( msg, "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); |
|
gEngfuncs.pfnConsolePrint( msg ); |
|
} |
|
|
|
// Is it the local player talking? |
|
if( entindex == -1 ) |
|
{ |
|
m_bTalking = !!bTalking; |
|
if( bTalking ) |
|
{ |
|
// Enable voice for them automatically if they try to talk. |
|
gEngfuncs.pfnClientCmd( "voice_modenable 1" ); |
|
} |
|
} |
|
else if( entindex == -2 ) |
|
{ |
|
m_bServerAcked = !!bTalking; |
|
} |
|
else if( entindex >= 0 && entindex <= VOICE_MAX_PLAYERS ) |
|
{ |
|
int iClient = entindex - 1; |
|
if( iClient < 0 ) |
|
return; |
|
|
|
CVoiceLabel *pLabel = FindVoiceLabel( iClient ); |
|
if( bTalking ) |
|
{ |
|
m_VoicePlayers[iClient] = true; |
|
m_VoiceEnabledPlayers[iClient] = true; |
|
|
|
// If we don't have a label for this guy yet, then create one. |
|
if( !pLabel ) |
|
{ |
|
if( pLabel = GetFreeVoiceLabel() ) |
|
{ |
|
// Get the name from the engine. |
|
hud_player_info_t info = {0}; |
|
|
|
GetPlayerInfo( entindex, &info ); |
|
|
|
char paddedName[512]; |
|
sprintf( paddedName, "%s ", info.name ); |
|
|
|
int color[3]; |
|
m_pHelper->GetPlayerTextColor( entindex, color ); |
|
|
|
if( pLabel->m_pBackground ) |
|
{ |
|
pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); |
|
pLabel->m_pBackground->setParent( *m_pParentPanel ); |
|
pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); |
|
} |
|
|
|
if( pLabel->m_pLabel ) |
|
{ |
|
pLabel->m_pLabel->setFgColor( 255, 255, 255, 0 ); |
|
pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); |
|
pLabel->m_pLabel->setText( paddedName ); |
|
} |
|
|
|
pLabel->m_clientindex = iClient; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
m_VoicePlayers[iClient] = false; |
|
|
|
// If we have a label for this guy, kill it. |
|
if( pLabel ) |
|
{ |
|
pLabel->m_pBackground->setVisible( false ); |
|
pLabel->m_clientindex = -1; |
|
} |
|
} |
|
} |
|
|
|
RepositionLabels(); |
|
} |
|
|
|
void CVoiceStatus::UpdateServerState( bool bForce ) |
|
{ |
|
// Can't do anything when we're not in a level. |
|
char const *pLevelName = gEngfuncs.pfnGetLevelName(); |
|
if( pLevelName[0] == 0 ) |
|
{ |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); |
|
} |
|
|
|
return; |
|
} |
|
|
|
int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat( "voice_modenable" ); |
|
if( bForce || m_bServerModEnable != bCVarModEnable ) |
|
{ |
|
m_bServerModEnable = bCVarModEnable; |
|
|
|
char str[256]; |
|
|
|
sprintf( str, "VModEnable %d", m_bServerModEnable ); |
|
ServerCmd( str ); |
|
|
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
char msg[256]; |
|
|
|
sprintf( msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str ); |
|
gEngfuncs.pfnConsolePrint( msg ); |
|
} |
|
} |
|
|
|
char str[2048] = "vban"; |
|
|
|
bool bChange = false; |
|
|
|
for( unsigned long dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++ ) |
|
{ |
|
unsigned long serverBanMask = 0; |
|
unsigned long banMask = 0; |
|
|
|
for( unsigned long i = 0; i < 32; i++ ) |
|
{ |
|
char playerID[16]; |
|
|
|
if( !gEngfuncs.GetPlayerUniqueID( i + 1, playerID ) ) |
|
continue; |
|
|
|
if( m_BanMgr.GetPlayerBan( playerID ) ) |
|
banMask |= 1 << i; |
|
|
|
if( m_ServerBannedPlayers[dw * 32 + i] ) |
|
serverBanMask |= 1 << i; |
|
} |
|
|
|
if( serverBanMask != banMask ) |
|
bChange = true; |
|
|
|
// Ok, the server needs to be updated. |
|
char numStr[512]; |
|
|
|
sprintf(numStr, " %x", banMask); |
|
|
|
strcat(str, numStr); |
|
} |
|
|
|
if( bChange || bForce ) |
|
{ |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
char msg[256]; |
|
|
|
sprintf( msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str ); |
|
|
|
gEngfuncs.pfnConsolePrint( msg ); |
|
} |
|
|
|
gEngfuncs.pfnServerCmdUnreliable( str ); // Tell the server.. |
|
} |
|
else |
|
{ |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); |
|
} |
|
} |
|
|
|
m_LastUpdateServerState = gEngfuncs.GetClientTime(); |
|
} |
|
|
|
void CVoiceStatus::UpdateSpeakerImage( Label *pLabel, int iPlayer ) |
|
{ |
|
m_pBanButtons[iPlayer - 1] = pLabel; |
|
UpdateBanButton(iPlayer - 1); |
|
} |
|
|
|
void CVoiceStatus::UpdateBanButton( int iClient ) |
|
{ |
|
Label *pPanel = m_pBanButtons[iClient]; |
|
|
|
if( !pPanel ) |
|
return; |
|
|
|
char playerID[16]; |
|
extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); |
|
|
|
if( !HACK_GetPlayerUniqueID( iClient + 1, playerID ) ) |
|
return; |
|
|
|
// Figure out if it's blinking or not. |
|
bool bBlink = fmod( m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY * 2 ) < SCOREBOARD_BLINK_FREQUENCY; |
|
bool bTalking = !!m_VoicePlayers[iClient]; |
|
bool bBanned = m_BanMgr.GetPlayerBan( playerID ); |
|
bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; |
|
|
|
// Get the appropriate image to display on the panel. |
|
if( bBanned ) |
|
{ |
|
pPanel->setImage( m_pScoreboardBanned ); |
|
} |
|
else if( bTalking ) |
|
{ |
|
if( bBlink ) |
|
{ |
|
pPanel->setImage( m_pScoreboardSpeaking2 ); |
|
} |
|
else |
|
{ |
|
pPanel->setImage( m_pScoreboardSpeaking ); |
|
} |
|
|
|
pPanel->setFgColor( 255, 170, 0, 1 ); |
|
} |
|
else if( bNeverSpoken ) |
|
{ |
|
pPanel->setImage( m_pScoreboardNeverSpoken ); |
|
pPanel->setFgColor( 100, 100, 100, 1 ); |
|
} |
|
else |
|
{ |
|
pPanel->setImage( m_pScoreboardNotSpeaking ); |
|
} |
|
} |
|
|
|
void CVoiceStatus::HandleVoiceMaskMsg( int iSize, void *pbuf ) |
|
{ |
|
BEGIN_READ( pbuf, iSize ); |
|
|
|
unsigned long dw; |
|
|
|
for( dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++ ) |
|
{ |
|
m_AudiblePlayers.SetDWord( dw, (unsigned long)READ_LONG() ); |
|
m_ServerBannedPlayers.SetDWord( dw, (unsigned long)READ_LONG() ); |
|
|
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
char str[256]; |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::HandleVoiceMaskMsg\n" ); |
|
|
|
sprintf( str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord( dw ) ); |
|
gEngfuncs.pfnConsolePrint( str ); |
|
|
|
sprintf( str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord( dw ) ); |
|
gEngfuncs.pfnConsolePrint( str ); |
|
} |
|
} |
|
|
|
m_bServerModEnable = READ_BYTE(); |
|
} |
|
|
|
void CVoiceStatus::HandleReqStateMsg( int iSize, void *pbuf ) |
|
{ |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::HandleReqStateMsg\n" ); |
|
} |
|
|
|
UpdateServerState( true ); |
|
} |
|
|
|
void CVoiceStatus::StartSquelchMode() |
|
{ |
|
if( m_bInSquelchMode ) |
|
return; |
|
|
|
m_bInSquelchMode = true; |
|
m_pHelper->UpdateCursorState(); |
|
} |
|
|
|
void CVoiceStatus::StopSquelchMode() |
|
{ |
|
m_bInSquelchMode = false; |
|
m_pHelper->UpdateCursorState(); |
|
} |
|
|
|
bool CVoiceStatus::IsInSquelchMode() |
|
{ |
|
return m_bInSquelchMode; |
|
} |
|
|
|
CVoiceLabel *CVoiceStatus::FindVoiceLabel( int clientindex ) |
|
{ |
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
{ |
|
if( m_Labels[i].m_clientindex == clientindex ) |
|
return &m_Labels[i]; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
CVoiceLabel *CVoiceStatus::GetFreeVoiceLabel() |
|
{ |
|
return FindVoiceLabel( -1 ); |
|
} |
|
|
|
void CVoiceStatus::RepositionLabels() |
|
{ |
|
// find starting position to draw from, along right-hand side of screen |
|
int y = ScreenHeight / 2; |
|
|
|
int iconWide = 8, iconTall = 8; |
|
if( m_pSpeakerLabelIcon ) |
|
{ |
|
m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); |
|
} |
|
|
|
// Reposition active labels. |
|
for( int i = 0; i < MAX_VOICE_SPEAKERS; i++ ) |
|
{ |
|
CVoiceLabel *pLabel = &m_Labels[i]; |
|
|
|
if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) |
|
{ |
|
if( pLabel->m_pBackground ) |
|
pLabel->m_pBackground->setVisible( false ); |
|
|
|
continue; |
|
} |
|
|
|
int textWide, textTall; |
|
|
|
pLabel->m_pLabel->getContentSize( textWide, textTall ); |
|
|
|
// Don't let it stretch too far across their screen. |
|
if( textWide > ( ScreenWidth * 2 ) / 3 ) |
|
textWide = ( ScreenWidth * 2 ) / 3; |
|
|
|
// Setup the background label to fit everything in. |
|
int border = 2; |
|
int bgWide = textWide + iconWide + border * 3; |
|
int bgTall = max( textTall, iconTall ) + border * 2; |
|
pLabel->m_pBackground->setBounds( ScreenWidth - bgWide - 8, y, bgWide, bgTall ); |
|
|
|
// Put the text at the left. |
|
pLabel->m_pLabel->setBounds( border, ( bgTall - textTall ) / 2, textWide, textTall ); |
|
|
|
// Put the icon at the right. |
|
int iconLeft = border + textWide + border; |
|
int iconTop = ( bgTall - iconTall ) / 2; |
|
if( pLabel->m_pIcon ) |
|
{ |
|
pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); |
|
pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); |
|
} |
|
|
|
y += bgTall + 2; |
|
} |
|
|
|
if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && ( m_bTalking || m_bServerAcked ) ) |
|
{ |
|
m_pLocalLabel->setParent( *m_pParentPanel ); |
|
m_pLocalLabel->setVisible( true ); |
|
|
|
if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
m_pLocalLabel->setImage( m_pAckBitmap ); |
|
else |
|
m_pLocalLabel->setImage( m_pLocalBitmap ); |
|
|
|
int sizeX, sizeY; |
|
|
|
m_pLocalBitmap->getSize( sizeX, sizeY ); |
|
|
|
int local_xPos = ScreenWidth - sizeX - 10; |
|
int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; |
|
|
|
m_pLocalLabel->setPos( local_xPos, local_yPos ); |
|
} |
|
else |
|
{ |
|
m_pLocalLabel->setVisible( false ); |
|
} |
|
} |
|
|
|
void CVoiceStatus::FreeBitmaps() |
|
{ |
|
// Delete all the images we have loaded. |
|
delete m_pLocalBitmap; |
|
m_pLocalBitmap = NULL; |
|
|
|
delete m_pAckBitmap; |
|
m_pAckBitmap = NULL; |
|
|
|
delete m_pSpeakerLabelIcon; |
|
m_pSpeakerLabelIcon = NULL; |
|
|
|
delete m_pScoreboardNeverSpoken; |
|
m_pScoreboardNeverSpoken = NULL; |
|
|
|
delete m_pScoreboardNotSpeaking; |
|
m_pScoreboardNotSpeaking = NULL; |
|
|
|
delete m_pScoreboardSpeaking; |
|
m_pScoreboardSpeaking = NULL; |
|
|
|
delete m_pScoreboardSpeaking2; |
|
m_pScoreboardSpeaking2 = NULL; |
|
|
|
delete m_pScoreboardSquelch; |
|
m_pScoreboardSquelch = NULL; |
|
|
|
delete m_pScoreboardBanned; |
|
m_pScoreboardBanned = NULL; |
|
|
|
// Clear references to the images in panels. |
|
for( int i = 0; i < VOICE_MAX_PLAYERS; i++ ) |
|
{ |
|
if( m_pBanButtons[i] ) |
|
{ |
|
m_pBanButtons[i]->setImage( NULL ); |
|
} |
|
} |
|
|
|
if( m_pLocalLabel ) |
|
m_pLocalLabel->setImage( NULL ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: returns true if the target client has been banned |
|
// Input : playerID - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CVoiceStatus::IsPlayerBlocked( int iPlayer ) |
|
{ |
|
char playerID[16]; |
|
|
|
if( !gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ) ) |
|
return false; |
|
|
|
return m_BanMgr.GetPlayerBan( playerID ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) |
|
// Input : playerID - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CVoiceStatus::IsPlayerAudible( int iPlayer ) |
|
{ |
|
return !!m_AudiblePlayers[iPlayer - 1]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: blocks/unblocks the target client from being heard |
|
// Input : playerID - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
void CVoiceStatus::SetPlayerBlockedState( int iPlayer, bool blocked ) |
|
{ |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); |
|
} |
|
|
|
char playerID[16]; |
|
|
|
if( !gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ) ) |
|
return; |
|
|
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); |
|
} |
|
|
|
// Squelch or (try to) unsquelch this player. |
|
if( gEngfuncs.pfnGetCvarFloat( "voice_clientdebug" ) ) |
|
{ |
|
char str[256]; |
|
|
|
sprintf( str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan( playerID ) ); |
|
gEngfuncs.pfnConsolePrint( str ); |
|
} |
|
|
|
m_BanMgr.SetPlayerBan( playerID, blocked ); |
|
UpdateServerState( false ); |
|
}
|
|
|