|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <string.h>
#include <stdio.h>
#include "voice_status.h"
#include "radio_status.h"
#include "c_playerresource.h"
#include "cliententitylist.h"
#include "c_baseplayer.h"
#include "materialsystem/imesh.h"
#include "view.h"
#include "materialsystem/imaterial.h"
#include "tier0/dbg.h"
#include "cdll_int.h"
#include "c_cs_player.h"
#include "menu.h" // for CHudMenu defs
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
// ---------------------------------------------------------------------- //
// The radio feedback manager for the client.
// ---------------------------------------------------------------------- //
static CRadioStatus s_RadioStatus;
//
//-----------------------------------------------------
//
// Stuff for the Radio Menus
static void radio1_f( void ); static void radio2_f( void ); static void radio3_f( void );
static ConCommand radio1( "radio1", radio1_f, "Opens a radio menu" ); static ConCommand radio2( "radio2", radio2_f, "Opens a radio menu" ); static ConCommand radio3( "radio3", radio3_f, "Opens a radio menu" ); static int g_whichMenu = 0;
//
//--------------------------------------------------------------
//
// These methods will bring up the radio menus from the client side.
// They mimic the old server commands of the same name, which used
// to require a round-trip causing latency and unreliability in
// menu responses. Only 1 message is sent to the server now which
// includes both the menu name and the selected item. The server
// is never informed that the menu has been displayed.
//
//--------------------------------------------------------------
//
void OpenRadioMenu( int index ) { // do not show the menu if the player is dead or is an observer
C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); if ( !pPlayer ) return;
if ( !pPlayer->IsAlive() || pPlayer->IsObserver() ) return;
CHudMenu *pMenu = (CHudMenu *) gHUD.FindElement( "CHudMenu" ); if ( !pMenu ) return;
g_whichMenu = index;
//
// the 0x23f and 0x3ff are masks that describes the keys that
// are valid. This will have to be changed if the menus change.
//
switch ( index ) { case 1: pMenu->ShowMenu( "#RadioA", 0x23f ); break; case 2: pMenu->ShowMenu( "#RadioB", 0x23f ); break; case 3: pMenu->ShowMenu( "#RadioC", 0x3ff ); break; default: g_whichMenu = 0; } }
static void radio1_f( void ) { OpenRadioMenu( 1 ); }
static void radio2_f( void ) { OpenRadioMenu( 2 ); }
static void radio3_f( void ) { OpenRadioMenu( 3 ); }
CON_COMMAND_F( menuselect, "menuselect", FCVAR_CLIENTCMD_CAN_EXECUTE ) { if ( args.ArgC() < 2 ) return;
if( g_whichMenu == 0 ) { // if we didn't have a menu open, maybe a plugin did. send it on to the server.
const char *cmd = VarArgs( "menuselect %s", args[1] ); engine->ServerCmd( cmd ); return; }
int whichEntry = atoi( args[ 1 ] );
switch( g_whichMenu ) { case 1: //RadioA
{ switch( whichEntry ) { case 1: // coverme
engine->ClientCmd( "coverme" ); break; case 2: // takepoint
engine->ClientCmd( "takepoint" ); break; case 3: // holdpos
engine->ClientCmd( "holdpos" ); break; case 4: // regroup
engine->ClientCmd( "regroup" ); break; case 5: // followme
engine->ClientCmd( "followme" ); break; case 6: // takingfire
engine->ClientCmd( "takingfire" ); break; } } break;
case 2: //RadioB
{ switch( whichEntry ) { case 1: // go
engine->ClientCmd( "go" ); break; case 2: // fallback
engine->ClientCmd( "fallback" ); break; case 3: // sticktog
engine->ClientCmd( "sticktog" ); break; case 4: // getinpos
engine->ClientCmd( "getinpos" ); break; case 5: // stormfront
engine->ClientCmd( "stormfront" ); break; case 6: // report
engine->ClientCmd( "report" ); break; } } break;
case 3: //RadioC
{ switch( whichEntry ) { case 1: // roger
engine->ClientCmd( "roger" ); break; case 2: // enemyspot
engine->ClientCmd( "enemyspot" ); break; case 3: // needbackup
engine->ClientCmd( "needbackup" ); break; case 4: // sectorclear
engine->ClientCmd( "sectorclear" ); break; case 5: // inposition
engine->ClientCmd( "inposition" ); break; case 6: // reportingin
engine->ClientCmd( "reportingin" ); break; case 7: // getout
engine->ClientCmd( "getout" ); break; case 8: // negative
engine->ClientCmd( "negative" ); break; case 9: // enemydown
engine->ClientCmd( "enemydown" ); break; } } break;
default: // if we didn't have a menu open, maybe a plugin did. send it on to the server.
const char *cmd = VarArgs( "menuselect %d", whichEntry ); engine->ServerCmd( cmd ); break; }
// reset menu
g_whichMenu = 0; }
//
//-----------------------------------------------------
//
CRadioStatus* RadioManager() { return &s_RadioStatus; }
// ---------------------------------------------------------------------- //
// CRadioStatus.
// ---------------------------------------------------------------------- //
CRadioStatus::CRadioStatus() { m_pHeadLabelMaterial = NULL; Q_memset(m_radioUntil, 0, sizeof(m_radioUntil)); Q_memset(m_voiceUntil, 0, sizeof(m_voiceUntil)); }
bool CRadioStatus::Init() { if ( !m_pHeadLabelMaterial ) { m_pHeadLabelMaterial = materials->FindMaterial( "sprites/radio", TEXTURE_GROUP_VGUI ); }
if ( IsErrorMaterial( m_pHeadLabelMaterial ) ) return false;
m_pHeadLabelMaterial->IncrementReferenceCount();
return true; }
void CRadioStatus::Shutdown() { if ( m_pHeadLabelMaterial ) m_pHeadLabelMaterial->DecrementReferenceCount();
m_pHeadLabelMaterial = NULL; }
void CRadioStatus::LevelInitPostEntity() { ExpireBotVoice( true ); Q_memset(m_radioUntil, 0, sizeof(m_radioUntil)); Q_memset(m_voiceUntil, 0, sizeof(m_voiceUntil)); }
void CRadioStatus::LevelShutdownPreEntity() { ExpireBotVoice( true ); Q_memset(m_radioUntil, 0, sizeof(m_radioUntil)); Q_memset(m_voiceUntil, 0, sizeof(m_voiceUntil)); }
extern float g_flHeadIconSize;
static float s_flHeadOffset = 3; static float s_flHeadIconSize = 7;
void CRadioStatus::DrawHeadLabels() { ExpireBotVoice();
if( !m_pHeadLabelMaterial ) return;
for(int i=0; i < VOICE_MAX_PLAYERS; i++) { if ( m_radioUntil[i] < gpGlobals->curtime ) continue;
IClientNetworkable *pClient = cl_entitylist->GetClientEntity( i+1 ); // Don't show an icon if the player is not in our PVS.
if ( !pClient || pClient->IsDormant() ) continue;
C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>(pClient); if( !pPlayer ) continue;
// Don't show an icon for dead or spectating players (ie: invisible entities).
if( pPlayer->IsPlayerDead() ) continue;
// Place it above his head.
Vector vOrigin = pPlayer->WorldSpaceCenter(); vOrigin.z += GetClientVoiceMgr()->GetHeadLabelOffset() + s_flHeadOffset;
if ( GetClientVoiceMgr()->IsPlayerSpeaking( i+1 ) ) { vOrigin.z += g_flHeadIconSize; } // Align it so it never points up or down.
Vector vUp( 0, 0, 1 ); Vector vRight = CurrentViewRight(); if ( fabs( vRight.z ) > 0.95 ) // don't draw it edge-on
continue;
vRight.z = 0; VectorNormalize( vRight );
float flSize = s_flHeadIconSize;
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_pHeadLabelMaterial ); IMesh *pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,0,0 ); meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * flSize)).Base() ); meshBuilder.AdvanceVertex();
meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,1,0 ); meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * flSize)).Base() ); meshBuilder.AdvanceVertex();
meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,1,1 ); meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * -flSize)).Base() ); meshBuilder.AdvanceVertex();
meshBuilder.Color3f( 1.0, 1.0, 1.0 ); meshBuilder.TexCoord2f( 0,0,1 ); meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * -flSize)).Base() ); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); } }
void CRadioStatus::UpdateRadioStatus(int entindex, float duration) { if(entindex > 0 && entindex <= VOICE_MAX_PLAYERS) { int iClient = entindex - 1; if(iClient < 0) return;
m_radioUntil[iClient] = gpGlobals->curtime + duration; } }
void CRadioStatus::UpdateVoiceStatus(int entindex, float duration) { if(entindex > 0 && entindex <= VOICE_MAX_PLAYERS) { int iClient = entindex - 1; if(iClient < 0) return;
m_voiceUntil[iClient] = gpGlobals->curtime + duration; GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, true ); } }
void CRadioStatus::ExpireBotVoice( bool force ) { for(int i=0; i < VOICE_MAX_PLAYERS; i++) { if ( m_voiceUntil[i] > 0.0f ) { bool expire = force;
C_CSPlayer *player = static_cast<C_CSPlayer*>( cl_entitylist->GetEnt(i+1) ); if ( !player ) { // player left the game
expire = true; } else if ( m_voiceUntil[i] < gpGlobals->curtime ) { // player is done speaking
expire = true; }
if ( expire ) { m_voiceUntil[i] = 0.0f; GetClientVoiceMgr()->UpdateSpeakerStatus( i+1, false ); } } } }
|