aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/clientmode_shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mp/src/game/client/clientmode_shared.cpp')
-rw-r--r--mp/src/game/client/clientmode_shared.cpp2788
1 files changed, 1394 insertions, 1394 deletions
diff --git a/mp/src/game/client/clientmode_shared.cpp b/mp/src/game/client/clientmode_shared.cpp
index 31acc934..a1d1127d 100644
--- a/mp/src/game/client/clientmode_shared.cpp
+++ b/mp/src/game/client/clientmode_shared.cpp
@@ -1,1394 +1,1394 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Normal HUD mode
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-
-
-#include "cbase.h"
-#include "clientmode_shared.h"
-#include "iinput.h"
-#include "view_shared.h"
-#include "iviewrender.h"
-#include "hud_basechat.h"
-#include "weapon_selection.h"
-#include <vgui/IVGui.h>
-#include <vgui/Cursor.h>
-#include <vgui/IPanel.h>
-#include <vgui/IInput.h>
-#include "engine/IEngineSound.h"
-#include <KeyValues.h>
-#include <vgui_controls/AnimationController.h>
-#include "vgui_int.h"
-#include "hud_macros.h"
-#include "hltvcamera.h"
-#include "particlemgr.h"
-#include "c_vguiscreen.h"
-#include "c_team.h"
-#include "c_rumble.h"
-#include "fmtstr.h"
-#include "achievementmgr.h"
-#include "c_playerresource.h"
-#include "cam_thirdperson.h"
-#include <vgui/ILocalize.h>
-#include "hud_vote.h"
-#include "ienginevgui.h"
-#include "headtrack/isourcevirtualreality.h"
-#if defined( _X360 )
-#include "xbox/xbox_console.h"
-#endif
-
-#if defined( REPLAY_ENABLED )
-#include "replay/replaycamera.h"
-#include "replay/ireplaysystem.h"
-#include "replay/iclientreplaycontext.h"
-#include "replay/ireplaymanager.h"
-#include "replay/replay.h"
-#include "replay/ienginereplay.h"
-#include "replay/vgui/replayreminderpanel.h"
-#include "replay/vgui/replaymessagepanel.h"
-#include "econ/econ_controls.h"
-#include "econ/confirm_dialog.h"
-extern IClientReplayContext *g_pClientReplayContext;
-extern ConVar replay_rendersetting_renderglow;
-#endif
-
-#if defined USES_ECON_ITEMS
-#include "econ_item_view.h"
-#endif
-
-#if defined( TF_CLIENT_DLL )
-#include "c_tf_player.h"
-#include "econ_item_description.h"
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10
-
-class CHudWeaponSelection;
-class CHudChat;
-class CHudVote;
-
-static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;
-
-ConVar cl_drawhud( "cl_drawhud", "1", FCVAR_CHEAT, "Enable the rendering of the hud" );
-ConVar hud_takesshots( "hud_takesshots", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Auto-save a scoreboard screenshot at the end of a map." );
-ConVar hud_freezecamhide( "hud_freezecamhide", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Hide the HUD during freeze-cam" );
-ConVar cl_show_num_particle_systems( "cl_show_num_particle_systems", "0", FCVAR_CLIENTDLL, "Display the number of active particle systems." );
-
-extern ConVar v_viewmodel_fov;
-extern ConVar voice_modenable;
-
-extern bool IsInCommentaryMode( void );
-
-#ifdef VOICE_VOX_ENABLE
-void VoxCallback( IConVar *var, const char *oldString, float oldFloat )
-{
- if ( engine && engine->IsConnected() )
- {
- ConVarRef voice_vox( var->GetName() );
- if ( voice_vox.GetBool() && voice_modenable.GetBool() )
- {
- engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" );
- }
- else
- {
- engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" );
- }
- }
-}
-ConVar voice_vox( "voice_vox", "0", FCVAR_ARCHIVE, "Voice chat uses a vox-style always on", true, 0, true, 1, VoxCallback );
-
-// --------------------------------------------------------------------------------- //
-// CVoxManager.
-// --------------------------------------------------------------------------------- //
-class CVoxManager : public CAutoGameSystem
-{
-public:
- CVoxManager() : CAutoGameSystem( "VoxManager" )
- {
- }
-
- virtual void LevelInitPostEntity( void )
- {
- if ( voice_vox.GetBool() && voice_modenable.GetBool() )
- {
- engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" );
- }
- }
-
- virtual void LevelShutdownPreEntity( void )
- {
- if ( voice_vox.GetBool() )
- {
- engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" );
- }
- }
-};
-
-static CVoxManager s_VoxManager;
-// --------------------------------------------------------------------------------- //
-#endif // VOICE_VOX_ENABLE
-
-CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." )
-{
- ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
- if ( !mode )
- return;
-
- mode->ReloadScheme();
-}
-
-#ifdef _DEBUG
-CON_COMMAND_F( crash, "Crash the client. Optional parameter -- type of crash:\n 0: read from NULL\n 1: write to NULL\n 2: DmCrashDump() (xbox360 only)", FCVAR_CHEAT )
-{
- int crashtype = 0;
- int dummy;
- if ( args.ArgC() > 1 )
- {
- crashtype = Q_atoi( args[1] );
- }
- switch (crashtype)
- {
- case 0:
- dummy = *((int *) NULL);
- Msg("Crashed! %d\n", dummy); // keeps dummy from optimizing out
- break;
- case 1:
- *((int *)NULL) = 42;
- break;
-#if defined( _X360 )
- case 2:
- XBX_CrashDump(false);
- break;
-#endif
- default:
- Msg("Unknown variety of crash. You have now failed to crash. I hope you're happy.\n");
- break;
- }
-}
-#endif // _DEBUG
-
-static void __MsgFunc_Rumble( bf_read &msg )
-{
- unsigned char waveformIndex;
- unsigned char rumbleData;
- unsigned char rumbleFlags;
-
- waveformIndex = msg.ReadByte();
- rumbleData = msg.ReadByte();
- rumbleFlags = msg.ReadByte();
-
- RumbleEffect( waveformIndex, rumbleData, rumbleFlags );
-}
-
-static void __MsgFunc_VGUIMenu( bf_read &msg )
-{
- char panelname[2048];
-
- msg.ReadString( panelname, sizeof(panelname) );
-
- bool bShow = msg.ReadByte()!=0;
-
- IViewPortPanel *viewport = gViewPortInterface->FindPanelByName( panelname );
-
- if ( !viewport )
- {
- // DevMsg("VGUIMenu: couldn't find panel '%s'.\n", panelname );
- return;
- }
-
- int count = msg.ReadByte();
-
- if ( count > 0 )
- {
- KeyValues *keys = new KeyValues("data");
-
- for ( int i=0; i<count; i++)
- {
- char name[255];
- char data[255];
-
- msg.ReadString( name, sizeof(name) );
- msg.ReadString( data, sizeof(data) );
-
- keys->SetString( name, data );
- }
-
- viewport->SetData( keys );
-
- keys->deleteThis();
- }
-
- // is the server telling us to show the scoreboard (at the end of a map)?
- if ( Q_stricmp( panelname, "scores" ) == 0 )
- {
- if ( hud_takesshots.GetBool() == true )
- {
- gHUD.SetScreenShotTime( gpGlobals->curtime + 1.0 ); // take a screenshot in 1 second
- }
- }
-
- // is the server trying to show an MOTD panel? Check that it's allowed right now.
- ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
- if ( Q_stricmp( panelname, PANEL_INFO ) == 0 && mode )
- {
- if ( !mode->IsInfoPanelAllowed() )
- {
- return;
- }
- else
- {
- mode->InfoPanelDisplayed();
- }
- }
-
- gViewPortInterface->ShowPanel( viewport, bShow );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-ClientModeShared::ClientModeShared()
-{
- m_pViewport = NULL;
- m_pChatElement = NULL;
- m_pWeaponSelection = NULL;
- m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;
-
-#if defined( REPLAY_ENABLED )
- m_pReplayReminderPanel = NULL;
- m_flReplayStartRecordTime = 0.0f;
- m_flReplayStopRecordTime = 0.0f;
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-ClientModeShared::~ClientModeShared()
-{
- delete m_pViewport;
-}
-
-void ClientModeShared::ReloadScheme( void )
-{
- m_pViewport->ReloadScheme( "resource/ClientScheme.res" );
- ClearKeyValuesCache();
-}
-
-
-//----------------------------------------------------------------------------
-// Purpose: Let the client mode set some vgui conditions
-//-----------------------------------------------------------------------------
-void ClientModeShared::ComputeVguiResConditions( KeyValues *pkvConditions )
-{
- if ( UseVR() )
- {
- pkvConditions->FindKey( "if_vr", true );
- }
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::Init()
-{
- m_pChatElement = ( CBaseHudChat * )GET_HUDELEMENT( CHudChat );
- Assert( m_pChatElement );
-
- m_pWeaponSelection = ( CBaseHudWeaponSelection * )GET_HUDELEMENT( CHudWeaponSelection );
- Assert( m_pWeaponSelection );
-
- KeyValuesAD pConditions( "conditions" );
- ComputeVguiResConditions( pConditions );
-
- // Derived ClientMode class must make sure m_Viewport is instantiated
- Assert( m_pViewport );
- m_pViewport->LoadControlSettings( "scripts/HudLayout.res", NULL, NULL, pConditions );
-
-#if defined( REPLAY_ENABLED )
- m_pReplayReminderPanel = GET_HUDELEMENT( CReplayReminderPanel );
- Assert( m_pReplayReminderPanel );
-#endif
-
- ListenForGameEvent( "player_connect" );
- ListenForGameEvent( "player_disconnect" );
- ListenForGameEvent( "player_team" );
- ListenForGameEvent( "server_cvar" );
- ListenForGameEvent( "player_changename" );
- ListenForGameEvent( "teamplay_broadcast_audio" );
- ListenForGameEvent( "achievement_earned" );
-
-#if defined( TF_CLIENT_DLL )
- ListenForGameEvent( "item_found" );
-#endif
-
-#if defined( REPLAY_ENABLED )
- ListenForGameEvent( "replay_startrecord" );
- ListenForGameEvent( "replay_endrecord" );
- ListenForGameEvent( "replay_replaysavailable" );
- ListenForGameEvent( "replay_servererror" );
- ListenForGameEvent( "game_newmap" );
-#endif
-
-#ifndef _XBOX
- HLTVCamera()->Init();
-#if defined( REPLAY_ENABLED )
- ReplayCamera()->Init();
-#endif
-#endif
-
- m_CursorNone = vgui::dc_none;
-
- HOOK_MESSAGE( VGUIMenu );
- HOOK_MESSAGE( Rumble );
-}
-
-
-void ClientModeShared::InitViewport()
-{
-}
-
-
-void ClientModeShared::VGui_Shutdown()
-{
- delete m_pViewport;
- m_pViewport = NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::Shutdown()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : frametime -
-// *cmd -
-//-----------------------------------------------------------------------------
-bool ClientModeShared::CreateMove( float flInputSampleTime, CUserCmd *cmd )
-{
- // Let the player override the view.
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if(!pPlayer)
- return true;
-
- // Let the player at it
- return pPlayer->CreateMove( flInputSampleTime, cmd );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pSetup -
-//-----------------------------------------------------------------------------
-void ClientModeShared::OverrideView( CViewSetup *pSetup )
-{
- QAngle camAngles;
-
- // Let the player override the view.
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if(!pPlayer)
- return;
-
- pPlayer->OverrideView( pSetup );
-
- if( ::input->CAM_IsThirdPerson() )
- {
- Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles();
- Vector cam_ofs_distance = g_ThirdPersonManager.GetFinalCameraOffset();
-
- cam_ofs_distance *= g_ThirdPersonManager.GetDistanceFraction();
-
- camAngles[ PITCH ] = cam_ofs[ PITCH ];
- camAngles[ YAW ] = cam_ofs[ YAW ];
- camAngles[ ROLL ] = 0;
-
- Vector camForward, camRight, camUp;
-
-
- if ( g_ThirdPersonManager.IsOverridingThirdPerson() == false )
- {
- engine->GetViewAngles( camAngles );
- }
-
- // get the forward vector
- AngleVectors( camAngles, &camForward, &camRight, &camUp );
-
- VectorMA( pSetup->origin, -cam_ofs_distance[0], camForward, pSetup->origin );
- VectorMA( pSetup->origin, cam_ofs_distance[1], camRight, pSetup->origin );
- VectorMA( pSetup->origin, cam_ofs_distance[2], camUp, pSetup->origin );
-
- // Override angles from third person camera
- VectorCopy( camAngles, pSetup->angles );
- }
- else if (::input->CAM_IsOrthographic())
- {
- pSetup->m_bOrtho = true;
- float w, h;
- ::input->CAM_OrthographicSize( w, h );
- w *= 0.5f;
- h *= 0.5f;
- pSetup->m_OrthoLeft = -w;
- pSetup->m_OrthoTop = -h;
- pSetup->m_OrthoRight = w;
- pSetup->m_OrthoBottom = h;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldDrawEntity(C_BaseEntity *pEnt)
-{
- return true;
-}
-
-bool ClientModeShared::ShouldDrawParticles( )
-{
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Allow weapons to override mouse input (for binoculars)
-//-----------------------------------------------------------------------------
-void ClientModeShared::OverrideMouseInput( float *x, float *y )
-{
- C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
- if ( pWeapon )
- {
- pWeapon->OverrideMouseInput( x, y );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldDrawViewModel()
-{
- return true;
-}
-
-bool ClientModeShared::ShouldDrawDetailObjects( )
-{
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns true if VR mode should black out everything outside the HUD.
-// This is used for things like sniper scopes and full screen UI
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldBlackoutAroundHUD()
-{
- return enginevgui->IsGameUIVisible();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Allows the client mode to override mouse control stuff in headtrack
-//-----------------------------------------------------------------------------
-HeadtrackMovementMode_t ClientModeShared::ShouldOverrideHeadtrackControl()
-{
- return HMM_NOOVERRIDE;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldDrawCrosshair( void )
-{
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Don't draw the current view entity if we are using the fake viewmodel instead
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldDrawLocalPlayer( C_BasePlayer *pPlayer )
-{
- if ( ( pPlayer->index == render->GetViewEntity() ) && !C_BasePlayer::ShouldDrawLocalPlayer() )
- return false;
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: The mode can choose to not draw fog
-//-----------------------------------------------------------------------------
-bool ClientModeShared::ShouldDrawFog( void )
-{
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::AdjustEngineViewport( int& x, int& y, int& width, int& height )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::PreRender( CViewSetup *pSetup )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::PostRender()
-{
- // Let the particle manager simulate things that haven't been simulated.
- ParticleMgr()->PostRender();
-}
-
-void ClientModeShared::PostRenderVGui()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::Update()
-{
-#if defined( REPLAY_ENABLED )
- UpdateReplayMessages();
-#endif
-
- if ( m_pViewport->IsVisible() != cl_drawhud.GetBool() )
- {
- m_pViewport->SetVisible( cl_drawhud.GetBool() );
- }
-
- UpdateRumbleEffects();
-
- if ( cl_show_num_particle_systems.GetBool() )
- {
- int nCount = 0;
-
- for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
- {
- const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
- CParticleSystemDefinition *pParticleSystem = g_pParticleSystemMgr->FindParticleSystem( pParticleSystemName );
- if ( !pParticleSystem )
- continue;
-
- for ( CParticleCollection *pCurCollection = pParticleSystem->FirstCollection();
- pCurCollection != NULL;
- pCurCollection = pCurCollection->GetNextCollectionUsingSameDef() )
- {
- ++nCount;
- }
- }
-
- engine->Con_NPrintf( 0, "# Active particle systems: %i", nCount );
- }
-}
-
-//-----------------------------------------------------------------------------
-// This processes all input before SV Move messages are sent
-//-----------------------------------------------------------------------------
-
-void ClientModeShared::ProcessInput(bool bActive)
-{
- gHUD.ProcessInput( bActive );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it.
-//-----------------------------------------------------------------------------
-int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
-{
- if ( engine->Con_IsVisible() )
- return 1;
-
- // Should we start typing a message?
- if ( pszCurrentBinding &&
- ( Q_strcmp( pszCurrentBinding, "messagemode" ) == 0 ||
- Q_strcmp( pszCurrentBinding, "say" ) == 0 ) )
- {
- if ( down )
- {
- StartMessageMode( MM_SAY );
- }
- return 0;
- }
- else if ( pszCurrentBinding &&
- ( Q_strcmp( pszCurrentBinding, "messagemode2" ) == 0 ||
- Q_strcmp( pszCurrentBinding, "say_team" ) == 0 ) )
- {
- if ( down )
- {
- StartMessageMode( MM_SAY_TEAM );
- }
- return 0;
- }
-
- // If we're voting...
-#ifdef VOTING_ENABLED
- CHudVote *pHudVote = GET_HUDELEMENT( CHudVote );
- if ( pHudVote && pHudVote->IsVisible() )
- {
- if ( !pHudVote->KeyInput( down, keynum, pszCurrentBinding ) )
- {
- return 0;
- }
- }
-#endif
-
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
-
- // if ingame spectator mode, let spectator input intercept key event here
- if( pPlayer &&
- ( pPlayer->GetObserverMode() > OBS_MODE_DEATHCAM ) &&
- !HandleSpectatorKeyInput( down, keynum, pszCurrentBinding ) )
- {
- return 0;
- }
-
- // Let game-specific hud elements get a crack at the key input
- if ( !HudElementKeyInput( down, keynum, pszCurrentBinding ) )
- {
- return 0;
- }
-
- C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
- if ( pWeapon )
- {
- return pWeapon->KeyInput( down, keynum, pszCurrentBinding );
- }
-
- return 1;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: See if spectator input occurred. Return 0 if the key is swallowed.
-//-----------------------------------------------------------------------------
-int ClientModeShared::HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
-{
- // we are in spectator mode, open spectator menu
- if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+duck" ) == 0 )
- {
- m_pViewport->ShowPanel( PANEL_SPECMENU, true );
- return 0; // we handled it, don't handle twice or send to server
- }
- else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack" ) == 0 )
- {
- engine->ClientCmd( "spec_next" );
- return 0;
- }
- else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack2" ) == 0 )
- {
- engine->ClientCmd( "spec_prev" );
- return 0;
- }
- else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+jump" ) == 0 )
- {
- engine->ClientCmd( "spec_mode" );
- return 0;
- }
- else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+strafe" ) == 0 )
- {
- HLTVCamera()->SetAutoDirector( true );
-#if defined( REPLAY_ENABLED )
- ReplayCamera()->SetAutoDirector( true );
-#endif
- return 0;
- }
-
- return 1;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: See if hud elements want key input. Return 0 if the key is swallowed
-//-----------------------------------------------------------------------------
-int ClientModeShared::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
-{
- if ( m_pWeaponSelection )
- {
- if ( !m_pWeaponSelection->KeyInput( down, keynum, pszCurrentBinding ) )
- {
- return 0;
- }
- }
-
-#if defined( REPLAY_ENABLED )
- if ( m_pReplayReminderPanel )
- {
- if ( m_pReplayReminderPanel->HudElementKeyInput( down, keynum, pszCurrentBinding ) )
- {
- return 0;
- }
- }
-#endif
-
- return 1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool ClientModeShared::DoPostScreenSpaceEffects( const CViewSetup *pSetup )
-{
-#if defined( REPLAY_ENABLED )
- if ( engine->IsPlayingDemo() )
- {
- if ( !replay_rendersetting_renderglow.GetBool() )
- return false;
- }
-#endif
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : vgui::Panel
-//-----------------------------------------------------------------------------
-vgui::Panel *ClientModeShared::GetMessagePanel()
-{
- if ( m_pChatElement && m_pChatElement->GetInputPanel() && m_pChatElement->GetInputPanel()->IsVisible() )
- return m_pChatElement->GetInputPanel();
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: The player has started to type a message
-//-----------------------------------------------------------------------------
-void ClientModeShared::StartMessageMode( int iMessageModeType )
-{
- // Can only show chat UI in multiplayer!!!
- if ( gpGlobals->maxClients == 1 )
- {
- return;
- }
- if ( m_pChatElement )
- {
- m_pChatElement->StartMessageMode( iMessageModeType );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *newmap -
-//-----------------------------------------------------------------------------
-void ClientModeShared::LevelInit( const char *newmap )
-{
- m_pViewport->GetAnimationController()->StartAnimationSequence("LevelInit");
-
- // Tell the Chat Interface
- if ( m_pChatElement )
- {
- m_pChatElement->LevelInit( newmap );
- }
-
- // we have to fake this event clientside, because clients connect after that
- IGameEvent *event = gameeventmanager->CreateEvent( "game_newmap" );
- if ( event )
- {
- event->SetString("mapname", newmap );
- gameeventmanager->FireEventClientSide( event );
- }
-
- // Create a vgui context for all of the in-game vgui panels...
- if ( s_hVGuiContext == DEFAULT_VGUI_CONTEXT )
- {
- s_hVGuiContext = vgui::ivgui()->CreateContext();
- }
-
- // Reset any player explosion/shock effects
- CLocalPlayerFilter filter;
- enginesound->SetPlayerDSP( filter, 0, true );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void ClientModeShared::LevelShutdown( void )
-{
- // Reset the third person camera so we don't crash
- g_ThirdPersonManager.Init();
-
- if ( m_pChatElement )
- {
- m_pChatElement->LevelShutdown();
- }
- if ( s_hVGuiContext != DEFAULT_VGUI_CONTEXT )
- {
- vgui::ivgui()->DestroyContext( s_hVGuiContext );
- s_hVGuiContext = DEFAULT_VGUI_CONTEXT;
- }
-
- // Reset any player explosion/shock effects
- CLocalPlayerFilter filter;
- enginesound->SetPlayerDSP( filter, 0, true );
-}
-
-
-void ClientModeShared::Enable()
-{
- vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();;
-
- // Add our viewport to the root panel.
- if( pRoot != 0 )
- {
- m_pViewport->SetParent( pRoot );
- }
-
- // All hud elements should be proportional
- // This sets that flag on the viewport and all child panels
- m_pViewport->SetProportional( true );
-
- m_pViewport->SetCursor( m_CursorNone );
- vgui::surface()->SetCursor( m_CursorNone );
-
- m_pViewport->SetVisible( true );
- if ( m_pViewport->IsKeyBoardInputEnabled() )
- {
- m_pViewport->RequestFocus();
- }
-
- Layout();
-}
-
-
-void ClientModeShared::Disable()
-{
- vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();;
-
- // Remove our viewport from the root panel.
- if( pRoot != 0 )
- {
- m_pViewport->SetParent( (vgui::VPANEL)NULL );
- }
-
- m_pViewport->SetVisible( false );
-}
-
-
-void ClientModeShared::Layout()
-{
- vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();
- int wide, tall;
-
- // Make the viewport fill the root panel.
- if( pRoot != 0 )
- {
- vgui::ipanel()->GetSize(pRoot, wide, tall);
-
- bool changed = wide != m_nRootSize[ 0 ] || tall != m_nRootSize[ 1 ];
- m_nRootSize[ 0 ] = wide;
- m_nRootSize[ 1 ] = tall;
-
- m_pViewport->SetBounds(0, 0, wide, tall);
- if ( changed )
- {
- ReloadScheme();
- }
- }
-}
-
-float ClientModeShared::GetViewModelFOV( void )
-{
- return v_viewmodel_fov.GetFloat();
-}
-
-class CHudChat;
-
-bool PlayerNameNotSetYet( const char *pszName )
-{
- if ( pszName && pszName[0] )
- {
- // Don't show "unconnected" if we haven't got the players name yet
- if ( Q_strnicmp(pszName,"unconnected",11) == 0 )
- return true;
- if ( Q_strnicmp(pszName,"NULLNAME",11) == 0 )
- return true;
- }
-
- return false;
-}
-
-void ClientModeShared::FireGameEvent( IGameEvent *event )
-{
- CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
-
- const char *eventname = event->GetName();
-
- if ( Q_strcmp( "player_connect", eventname ) == 0 )
- {
- if ( !hudChat )
- return;
- if ( PlayerNameNotSetYet(event->GetString("name")) )
- return;
-
- if ( !IsInCommentaryMode() )
- {
- wchar_t wszLocalized[100];
- wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("name"), wszPlayerName, sizeof(wszPlayerName) );
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_game" ), 1, wszPlayerName );
-
- char szLocalized[100];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
-
- hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized );
- }
- }
- else if ( Q_strcmp( "player_disconnect", eventname ) == 0 )
- {
- C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
-
- if ( !hudChat || !pPlayer )
- return;
- if ( PlayerNameNotSetYet(event->GetString("name")) )
- return;
-
- if ( !IsInCommentaryMode() )
- {
- wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
-
- wchar_t wszReason[64];
- const char *pszReason = event->GetString( "reason" );
- if ( pszReason && ( pszReason[0] == '#' ) && g_pVGuiLocalize->Find( pszReason ) )
- {
- V_wcsncpy( wszReason, g_pVGuiLocalize->Find( pszReason ), sizeof( wszReason ) );
- }
- else
- {
- g_pVGuiLocalize->ConvertANSIToUnicode( pszReason, wszReason, sizeof(wszReason) );
- }
-
- wchar_t wszLocalized[100];
- if (IsPC())
- {
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 2, wszPlayerName, wszReason );
- }
- else
- {
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 1, wszPlayerName );
- }
-
- char szLocalized[100];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
-
- hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized );
- }
- }
- else if ( Q_strcmp( "player_team", eventname ) == 0 )
- {
- C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
- if ( !hudChat )
- return;
-
- bool bDisconnected = event->GetBool("disconnect");
-
- if ( bDisconnected )
- return;
-
- int team = event->GetInt( "team" );
- bool bAutoTeamed = event->GetInt( "autoteam", false );
- bool bSilent = event->GetInt( "silent", false );
-
- const char *pszName = event->GetString( "name" );
- if ( PlayerNameNotSetYet( pszName ) )
- return;
-
- if ( !bSilent )
- {
- wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( pszName, wszPlayerName, sizeof(wszPlayerName) );
-
- wchar_t wszTeam[64];
- C_Team *pTeam = GetGlobalTeam( team );
- if ( pTeam )
- {
- g_pVGuiLocalize->ConvertANSIToUnicode( pTeam->Get_Name(), wszTeam, sizeof(wszTeam) );
- }
- else
- {
- _snwprintf ( wszTeam, sizeof( wszTeam ) / sizeof( wchar_t ), L"%d", team );
- }
-
- if ( !IsInCommentaryMode() )
- {
- wchar_t wszLocalized[100];
- if ( bAutoTeamed )
- {
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_autoteam" ), 2, wszPlayerName, wszTeam );
- }
- else
- {
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_team" ), 2, wszPlayerName, wszTeam );
- }
-
- char szLocalized[100];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
-
- hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s", szLocalized );
- }
- }
-
- if ( pPlayer && pPlayer->IsLocalPlayer() )
- {
- // that's me
- pPlayer->TeamChange( team );
- }
- }
- else if ( Q_strcmp( "player_changename", eventname ) == 0 )
- {
- if ( !hudChat )
- return;
-
- const char *pszOldName = event->GetString("oldname");
- if ( PlayerNameNotSetYet(pszOldName) )
- return;
-
- wchar_t wszOldName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( pszOldName, wszOldName, sizeof(wszOldName) );
-
- wchar_t wszNewName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString( "newname" ), wszNewName, sizeof(wszNewName) );
-
- wchar_t wszLocalized[100];
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_changed_name" ), 2, wszOldName, wszNewName );
-
- char szLocalized[100];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
-
- hudChat->Printf( CHAT_FILTER_NAMECHANGE, "%s", szLocalized );
- }
- else if (Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 )
- {
- int team = event->GetInt( "team" );
-
- bool bValidTeam = false;
-
- if ( (GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == team) )
- {
- bValidTeam = true;
- }
-
- //If we're in the spectator team then we should be getting whatever messages the person I'm spectating gets.
- if ( bValidTeam == false )
- {
- CBasePlayer *pSpectatorTarget = UTIL_PlayerByIndex( GetSpectatorTarget() );
-
- if ( pSpectatorTarget && (GetSpectatorMode() == OBS_MODE_IN_EYE || GetSpectatorMode() == OBS_MODE_CHASE) )
- {
- if ( pSpectatorTarget->GetTeamNumber() == team )
- {
- bValidTeam = true;
- }
- }
- }
-
- if ( team == 0 && GetLocalTeam() > 0 )
- {
- bValidTeam = false;
- }
-
- if ( team == 255 )
- {
- bValidTeam = true;
- }
-
- if ( bValidTeam == true )
- {
- EmitSound_t et;
- et.m_pSoundName = event->GetString("sound");
- et.m_nFlags = event->GetInt("additional_flags");
-
- CLocalPlayerFilter filter;
- C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, et );
- }
- }
- else if ( Q_strcmp( "server_cvar", eventname ) == 0 )
- {
- if ( !IsInCommentaryMode() )
- {
- wchar_t wszCvarName[64];
- g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarname"), wszCvarName, sizeof(wszCvarName) );
-
- wchar_t wszCvarValue[64];
- g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarvalue"), wszCvarValue, sizeof(wszCvarValue) );
-
- wchar_t wszLocalized[256];
- g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_server_cvar_changed" ), 2, wszCvarName, wszCvarValue );
-
- char szLocalized[256];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
-
- hudChat->Printf( CHAT_FILTER_SERVERMSG, "%s", szLocalized );
- }
- }
- else if ( Q_strcmp( "achievement_earned", eventname ) == 0 )
- {
- int iPlayerIndex = event->GetInt( "player" );
- C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
- int iAchievement = event->GetInt( "achievement" );
-
- if ( !hudChat || !pPlayer )
- return;
-
- if ( !IsInCommentaryMode() )
- {
- CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr *>( engine->GetAchievementMgr() );
- if ( !pAchievementMgr )
- return;
-
- IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement );
- if ( pAchievement )
- {
- if ( !pPlayer->IsDormant() && pPlayer->ShouldAnnounceAchievement() )
- {
- pPlayer->SetNextAchievementAnnounceTime( gpGlobals->curtime + ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME );
-
- // no particle effect if the local player is the one with the achievement or the player is dead
- if ( !pPlayer->IsLocalPlayer() && pPlayer->IsAlive() )
- {
- //tagES using the "head" attachment won't work for CS and DoD
- pPlayer->ParticleProp()->Create( "achieved", PATTACH_POINT_FOLLOW, "head" );
- }
-
- pPlayer->OnAchievementAchieved( iAchievement );
- }
-
- if ( g_PR )
- {
- wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) );
-
- const wchar_t *pchLocalizedAchievement = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievement->GetName() );
- if ( pchLocalizedAchievement )
- {
- wchar_t wszLocalizedString[128];
- g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#Achievement_Earned" ), 2, wszPlayerName, pchLocalizedAchievement );
-
- char szLocalized[128];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) );
-
- hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized );
- }
- }
- }
- }
- }
-#if defined( TF_CLIENT_DLL )
- else if ( Q_strcmp( "item_found", eventname ) == 0 )
- {
- int iPlayerIndex = event->GetInt( "player" );
- entityquality_t iItemQuality = event->GetInt( "quality" );
- int iMethod = event->GetInt( "method" );
- int iItemDef = event->GetInt( "itemdef" );
- C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
- const GameItemDefinition_t *pItemDefinition = dynamic_cast<GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( iItemDef ) );
-
- if ( !pPlayer || !pItemDefinition )
- return;
-
- if ( g_PR )
- {
- wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
- g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) );
-
- if ( iMethod < 0 || iMethod >= ARRAYSIZE( g_pszItemFoundMethodStrings ) )
- {
- iMethod = 0;
- }
-
- const char *pszLocString = g_pszItemFoundMethodStrings[iMethod];
- if ( pszLocString )
- {
- wchar_t wszItemFound[256];
- _snwprintf( wszItemFound, ARRAYSIZE( wszItemFound ), L"%ls", g_pVGuiLocalize->Find( pszLocString ) );
-
- wchar_t *colorMarker = wcsstr( wszItemFound, L"::" );
- if ( colorMarker )
- {
- const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)iItemQuality );
- if ( pszQualityColorString )
- {
- hudChat->SetCustomColor( pszQualityColorString );
- *(colorMarker+1) = COLOR_CUSTOM;
- }
- }
-
- // TODO: Update the localization strings to only have two format parameters since that's all we need.
- wchar_t wszLocalizedString[256];
- g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItemDefinition, iItemQuality ).GetFullName(), L"" );
-
- char szLocalized[256];
- g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) );
-
- hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized );
- }
- }
- }
-#endif
-#if defined( REPLAY_ENABLED )
- else if ( !V_strcmp( "replay_servererror", eventname ) )
- {
- DisplayReplayMessage( event->GetString( "error", "#Replay_DefaultServerError" ), replay_msgduration_error.GetFloat(), true, NULL, false );
- }
- else if ( !V_strcmp( "replay_startrecord", eventname ) )
- {
- m_flReplayStartRecordTime = gpGlobals->curtime;
- }
- else if ( !V_strcmp( "replay_endrecord", eventname ) )
- {
- m_flReplayStopRecordTime = gpGlobals->curtime;
- }
- else if ( !V_strcmp( "replay_replaysavailable", eventname ) )
- {
- DisplayReplayMessage( "#Replay_ReplaysAvailable", replay_msgduration_replaysavailable.GetFloat(), false, NULL, false );
- }
-
- else if ( !V_strcmp( "game_newmap", eventname ) )
- {
- // Make sure the instance count is reset to 0. Sometimes the count stay in sync and we get replay messages displaying lower than they should.
- CReplayMessagePanel::RemoveAll();
- }
-#endif
-
- else
- {
- DevMsg( 2, "Unhandled GameEvent in ClientModeShared::FireGameEvent - %s\n", event->GetName() );
- }
-}
-
-void ClientModeShared::UpdateReplayMessages()
-{
-#if defined( REPLAY_ENABLED )
- // Received a replay_startrecord event?
- if ( m_flReplayStartRecordTime != 0.0f )
- {
- DisplayReplayMessage( "#Replay_StartRecord", replay_msgduration_startrecord.GetFloat(), true, "replay\\startrecord.mp3", false );
-
- m_flReplayStartRecordTime = 0.0f;
- m_flReplayStopRecordTime = 0.0f;
- }
-
- // Received a replay_endrecord event?
- if ( m_flReplayStopRecordTime != 0.0f )
- {
- DisplayReplayMessage( "#Replay_EndRecord", replay_msgduration_stoprecord.GetFloat(), true, "replay\\stoprecord.wav", false );
-
- // Hide the replay reminder
- if ( m_pReplayReminderPanel )
- {
- m_pReplayReminderPanel->Hide();
- }
-
- m_flReplayStopRecordTime = 0.0f;
- }
-
- if ( !engine->IsConnected() )
- {
- ClearReplayMessageList();
- }
-#endif
-}
-
-void ClientModeShared::ClearReplayMessageList()
-{
-#if defined( REPLAY_ENABLED )
- CReplayMessagePanel::RemoveAll();
-#endif
-}
-
-void ClientModeShared::DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent,
- const char *pSound, bool bDlg )
-{
-#if defined( REPLAY_ENABLED )
- // Don't display during replay playback, and don't allow more than 4 at a time
- const bool bInReplay = g_pEngineClientReplay->IsPlayingReplayDemo();
- if ( bInReplay || ( !bDlg && CReplayMessagePanel::InstanceCount() >= 4 ) )
- return;
-
- // Use default duration?
- if ( flDuration == -1.0f )
- {
- flDuration = replay_msgduration_misc.GetFloat();
- }
-
- // Display a replay message
- if ( bDlg )
- {
- if ( engine->IsInGame() )
- {
- Panel *pPanel = new CReplayMessageDlg( pLocalizeName );
- pPanel->SetVisible( true );
- pPanel->MakePopup();
- pPanel->MoveToFront();
- pPanel->SetKeyBoardInputEnabled( true );
- pPanel->SetMouseInputEnabled( true );
-#if defined( TF_CLIENT_DLL )
- TFModalStack()->PushModal( pPanel );
-#endif
- }
- else
- {
- ShowMessageBox( "#Replay_GenericMsgTitle", pLocalizeName, "#GameUI_OK" );
- }
- }
- else
- {
- CReplayMessagePanel *pMsgPanel = new CReplayMessagePanel( pLocalizeName, flDuration, bUrgent );
- pMsgPanel->Show();
- }
-
- // Play a sound if appropriate
- if ( pSound )
- {
- surface()->PlaySound( pSound );
- }
-#endif
-}
-
-void ClientModeShared::DisplayReplayReminder()
-{
-#if defined( REPLAY_ENABLED )
- if ( m_pReplayReminderPanel && g_pReplay->IsRecording() )
- {
- // Only display the panel if we haven't already requested a replay for the given life
- CReplay *pCurLifeReplay = static_cast< CReplay * >( g_pClientReplayContext->GetReplayManager()->GetReplayForCurrentLife() );
- if ( pCurLifeReplay && !pCurLifeReplay->m_bRequestedByUser && !pCurLifeReplay->m_bSaved )
- {
- m_pReplayReminderPanel->Show();
- }
- }
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-// In-game VGUI context
-//-----------------------------------------------------------------------------
-void ClientModeShared::ActivateInGameVGuiContext( vgui::Panel *pPanel )
-{
- vgui::ivgui()->AssociatePanelWithContext( s_hVGuiContext, pPanel->GetVPanel() );
- vgui::ivgui()->ActivateContext( s_hVGuiContext );
-}
-
-void ClientModeShared::DeactivateInGameVGuiContext()
-{
- vgui::ivgui()->ActivateContext( DEFAULT_VGUI_CONTEXT );
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Normal HUD mode
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "clientmode_shared.h"
+#include "iinput.h"
+#include "view_shared.h"
+#include "iviewrender.h"
+#include "hud_basechat.h"
+#include "weapon_selection.h"
+#include <vgui/IVGui.h>
+#include <vgui/Cursor.h>
+#include <vgui/IPanel.h>
+#include <vgui/IInput.h>
+#include "engine/IEngineSound.h"
+#include <KeyValues.h>
+#include <vgui_controls/AnimationController.h>
+#include "vgui_int.h"
+#include "hud_macros.h"
+#include "hltvcamera.h"
+#include "particlemgr.h"
+#include "c_vguiscreen.h"
+#include "c_team.h"
+#include "c_rumble.h"
+#include "fmtstr.h"
+#include "achievementmgr.h"
+#include "c_playerresource.h"
+#include "cam_thirdperson.h"
+#include <vgui/ILocalize.h>
+#include "hud_vote.h"
+#include "ienginevgui.h"
+#include "headtrack/isourcevirtualreality.h"
+#if defined( _X360 )
+#include "xbox/xbox_console.h"
+#endif
+
+#if defined( REPLAY_ENABLED )
+#include "replay/replaycamera.h"
+#include "replay/ireplaysystem.h"
+#include "replay/iclientreplaycontext.h"
+#include "replay/ireplaymanager.h"
+#include "replay/replay.h"
+#include "replay/ienginereplay.h"
+#include "replay/vgui/replayreminderpanel.h"
+#include "replay/vgui/replaymessagepanel.h"
+#include "econ/econ_controls.h"
+#include "econ/confirm_dialog.h"
+extern IClientReplayContext *g_pClientReplayContext;
+extern ConVar replay_rendersetting_renderglow;
+#endif
+
+#if defined USES_ECON_ITEMS
+#include "econ_item_view.h"
+#endif
+
+#if defined( TF_CLIENT_DLL )
+#include "c_tf_player.h"
+#include "econ_item_description.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10
+
+class CHudWeaponSelection;
+class CHudChat;
+class CHudVote;
+
+static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT;
+
+ConVar cl_drawhud( "cl_drawhud", "1", FCVAR_CHEAT, "Enable the rendering of the hud" );
+ConVar hud_takesshots( "hud_takesshots", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Auto-save a scoreboard screenshot at the end of a map." );
+ConVar hud_freezecamhide( "hud_freezecamhide", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Hide the HUD during freeze-cam" );
+ConVar cl_show_num_particle_systems( "cl_show_num_particle_systems", "0", FCVAR_CLIENTDLL, "Display the number of active particle systems." );
+
+extern ConVar v_viewmodel_fov;
+extern ConVar voice_modenable;
+
+extern bool IsInCommentaryMode( void );
+
+#ifdef VOICE_VOX_ENABLE
+void VoxCallback( IConVar *var, const char *oldString, float oldFloat )
+{
+ if ( engine && engine->IsConnected() )
+ {
+ ConVarRef voice_vox( var->GetName() );
+ if ( voice_vox.GetBool() && voice_modenable.GetBool() )
+ {
+ engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" );
+ }
+ else
+ {
+ engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" );
+ }
+ }
+}
+ConVar voice_vox( "voice_vox", "0", FCVAR_ARCHIVE, "Voice chat uses a vox-style always on", true, 0, true, 1, VoxCallback );
+
+// --------------------------------------------------------------------------------- //
+// CVoxManager.
+// --------------------------------------------------------------------------------- //
+class CVoxManager : public CAutoGameSystem
+{
+public:
+ CVoxManager() : CAutoGameSystem( "VoxManager" )
+ {
+ }
+
+ virtual void LevelInitPostEntity( void )
+ {
+ if ( voice_vox.GetBool() && voice_modenable.GetBool() )
+ {
+ engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" );
+ }
+ }
+
+ virtual void LevelShutdownPreEntity( void )
+ {
+ if ( voice_vox.GetBool() )
+ {
+ engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" );
+ }
+ }
+};
+
+static CVoxManager s_VoxManager;
+// --------------------------------------------------------------------------------- //
+#endif // VOICE_VOX_ENABLE
+
+CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." )
+{
+ ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
+ if ( !mode )
+ return;
+
+ mode->ReloadScheme();
+}
+
+#ifdef _DEBUG
+CON_COMMAND_F( crash, "Crash the client. Optional parameter -- type of crash:\n 0: read from NULL\n 1: write to NULL\n 2: DmCrashDump() (xbox360 only)", FCVAR_CHEAT )
+{
+ int crashtype = 0;
+ int dummy;
+ if ( args.ArgC() > 1 )
+ {
+ crashtype = Q_atoi( args[1] );
+ }
+ switch (crashtype)
+ {
+ case 0:
+ dummy = *((int *) NULL);
+ Msg("Crashed! %d\n", dummy); // keeps dummy from optimizing out
+ break;
+ case 1:
+ *((int *)NULL) = 42;
+ break;
+#if defined( _X360 )
+ case 2:
+ XBX_CrashDump(false);
+ break;
+#endif
+ default:
+ Msg("Unknown variety of crash. You have now failed to crash. I hope you're happy.\n");
+ break;
+ }
+}
+#endif // _DEBUG
+
+static void __MsgFunc_Rumble( bf_read &msg )
+{
+ unsigned char waveformIndex;
+ unsigned char rumbleData;
+ unsigned char rumbleFlags;
+
+ waveformIndex = msg.ReadByte();
+ rumbleData = msg.ReadByte();
+ rumbleFlags = msg.ReadByte();
+
+ RumbleEffect( waveformIndex, rumbleData, rumbleFlags );
+}
+
+static void __MsgFunc_VGUIMenu( bf_read &msg )
+{
+ char panelname[2048];
+
+ msg.ReadString( panelname, sizeof(panelname) );
+
+ bool bShow = msg.ReadByte()!=0;
+
+ IViewPortPanel *viewport = gViewPortInterface->FindPanelByName( panelname );
+
+ if ( !viewport )
+ {
+ // DevMsg("VGUIMenu: couldn't find panel '%s'.\n", panelname );
+ return;
+ }
+
+ int count = msg.ReadByte();
+
+ if ( count > 0 )
+ {
+ KeyValues *keys = new KeyValues("data");
+
+ for ( int i=0; i<count; i++)
+ {
+ char name[255];
+ char data[255];
+
+ msg.ReadString( name, sizeof(name) );
+ msg.ReadString( data, sizeof(data) );
+
+ keys->SetString( name, data );
+ }
+
+ viewport->SetData( keys );
+
+ keys->deleteThis();
+ }
+
+ // is the server telling us to show the scoreboard (at the end of a map)?
+ if ( Q_stricmp( panelname, "scores" ) == 0 )
+ {
+ if ( hud_takesshots.GetBool() == true )
+ {
+ gHUD.SetScreenShotTime( gpGlobals->curtime + 1.0 ); // take a screenshot in 1 second
+ }
+ }
+
+ // is the server trying to show an MOTD panel? Check that it's allowed right now.
+ ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
+ if ( Q_stricmp( panelname, PANEL_INFO ) == 0 && mode )
+ {
+ if ( !mode->IsInfoPanelAllowed() )
+ {
+ return;
+ }
+ else
+ {
+ mode->InfoPanelDisplayed();
+ }
+ }
+
+ gViewPortInterface->ShowPanel( viewport, bShow );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ClientModeShared::ClientModeShared()
+{
+ m_pViewport = NULL;
+ m_pChatElement = NULL;
+ m_pWeaponSelection = NULL;
+ m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1;
+
+#if defined( REPLAY_ENABLED )
+ m_pReplayReminderPanel = NULL;
+ m_flReplayStartRecordTime = 0.0f;
+ m_flReplayStopRecordTime = 0.0f;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ClientModeShared::~ClientModeShared()
+{
+ delete m_pViewport;
+}
+
+void ClientModeShared::ReloadScheme( void )
+{
+ m_pViewport->ReloadScheme( "resource/ClientScheme.res" );
+ ClearKeyValuesCache();
+}
+
+
+//----------------------------------------------------------------------------
+// Purpose: Let the client mode set some vgui conditions
+//-----------------------------------------------------------------------------
+void ClientModeShared::ComputeVguiResConditions( KeyValues *pkvConditions )
+{
+ if ( UseVR() )
+ {
+ pkvConditions->FindKey( "if_vr", true );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::Init()
+{
+ m_pChatElement = ( CBaseHudChat * )GET_HUDELEMENT( CHudChat );
+ Assert( m_pChatElement );
+
+ m_pWeaponSelection = ( CBaseHudWeaponSelection * )GET_HUDELEMENT( CHudWeaponSelection );
+ Assert( m_pWeaponSelection );
+
+ KeyValuesAD pConditions( "conditions" );
+ ComputeVguiResConditions( pConditions );
+
+ // Derived ClientMode class must make sure m_Viewport is instantiated
+ Assert( m_pViewport );
+ m_pViewport->LoadControlSettings( "scripts/HudLayout.res", NULL, NULL, pConditions );
+
+#if defined( REPLAY_ENABLED )
+ m_pReplayReminderPanel = GET_HUDELEMENT( CReplayReminderPanel );
+ Assert( m_pReplayReminderPanel );
+#endif
+
+ ListenForGameEvent( "player_connect" );
+ ListenForGameEvent( "player_disconnect" );
+ ListenForGameEvent( "player_team" );
+ ListenForGameEvent( "server_cvar" );
+ ListenForGameEvent( "player_changename" );
+ ListenForGameEvent( "teamplay_broadcast_audio" );
+ ListenForGameEvent( "achievement_earned" );
+
+#if defined( TF_CLIENT_DLL )
+ ListenForGameEvent( "item_found" );
+#endif
+
+#if defined( REPLAY_ENABLED )
+ ListenForGameEvent( "replay_startrecord" );
+ ListenForGameEvent( "replay_endrecord" );
+ ListenForGameEvent( "replay_replaysavailable" );
+ ListenForGameEvent( "replay_servererror" );
+ ListenForGameEvent( "game_newmap" );
+#endif
+
+#ifndef _XBOX
+ HLTVCamera()->Init();
+#if defined( REPLAY_ENABLED )
+ ReplayCamera()->Init();
+#endif
+#endif
+
+ m_CursorNone = vgui::dc_none;
+
+ HOOK_MESSAGE( VGUIMenu );
+ HOOK_MESSAGE( Rumble );
+}
+
+
+void ClientModeShared::InitViewport()
+{
+}
+
+
+void ClientModeShared::VGui_Shutdown()
+{
+ delete m_pViewport;
+ m_pViewport = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::Shutdown()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frametime -
+// *cmd -
+//-----------------------------------------------------------------------------
+bool ClientModeShared::CreateMove( float flInputSampleTime, CUserCmd *cmd )
+{
+ // Let the player override the view.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return true;
+
+ // Let the player at it
+ return pPlayer->CreateMove( flInputSampleTime, cmd );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pSetup -
+//-----------------------------------------------------------------------------
+void ClientModeShared::OverrideView( CViewSetup *pSetup )
+{
+ QAngle camAngles;
+
+ // Let the player override the view.
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if(!pPlayer)
+ return;
+
+ pPlayer->OverrideView( pSetup );
+
+ if( ::input->CAM_IsThirdPerson() )
+ {
+ Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles();
+ Vector cam_ofs_distance = g_ThirdPersonManager.GetFinalCameraOffset();
+
+ cam_ofs_distance *= g_ThirdPersonManager.GetDistanceFraction();
+
+ camAngles[ PITCH ] = cam_ofs[ PITCH ];
+ camAngles[ YAW ] = cam_ofs[ YAW ];
+ camAngles[ ROLL ] = 0;
+
+ Vector camForward, camRight, camUp;
+
+
+ if ( g_ThirdPersonManager.IsOverridingThirdPerson() == false )
+ {
+ engine->GetViewAngles( camAngles );
+ }
+
+ // get the forward vector
+ AngleVectors( camAngles, &camForward, &camRight, &camUp );
+
+ VectorMA( pSetup->origin, -cam_ofs_distance[0], camForward, pSetup->origin );
+ VectorMA( pSetup->origin, cam_ofs_distance[1], camRight, pSetup->origin );
+ VectorMA( pSetup->origin, cam_ofs_distance[2], camUp, pSetup->origin );
+
+ // Override angles from third person camera
+ VectorCopy( camAngles, pSetup->angles );
+ }
+ else if (::input->CAM_IsOrthographic())
+ {
+ pSetup->m_bOrtho = true;
+ float w, h;
+ ::input->CAM_OrthographicSize( w, h );
+ w *= 0.5f;
+ h *= 0.5f;
+ pSetup->m_OrthoLeft = -w;
+ pSetup->m_OrthoTop = -h;
+ pSetup->m_OrthoRight = w;
+ pSetup->m_OrthoBottom = h;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldDrawEntity(C_BaseEntity *pEnt)
+{
+ return true;
+}
+
+bool ClientModeShared::ShouldDrawParticles( )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Allow weapons to override mouse input (for binoculars)
+//-----------------------------------------------------------------------------
+void ClientModeShared::OverrideMouseInput( float *x, float *y )
+{
+ C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
+ if ( pWeapon )
+ {
+ pWeapon->OverrideMouseInput( x, y );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldDrawViewModel()
+{
+ return true;
+}
+
+bool ClientModeShared::ShouldDrawDetailObjects( )
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if VR mode should black out everything outside the HUD.
+// This is used for things like sniper scopes and full screen UI
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldBlackoutAroundHUD()
+{
+ return enginevgui->IsGameUIVisible();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Allows the client mode to override mouse control stuff in headtrack
+//-----------------------------------------------------------------------------
+HeadtrackMovementMode_t ClientModeShared::ShouldOverrideHeadtrackControl()
+{
+ return HMM_NOOVERRIDE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldDrawCrosshair( void )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Don't draw the current view entity if we are using the fake viewmodel instead
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldDrawLocalPlayer( C_BasePlayer *pPlayer )
+{
+ if ( ( pPlayer->index == render->GetViewEntity() ) && !C_BasePlayer::ShouldDrawLocalPlayer() )
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: The mode can choose to not draw fog
+//-----------------------------------------------------------------------------
+bool ClientModeShared::ShouldDrawFog( void )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::AdjustEngineViewport( int& x, int& y, int& width, int& height )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::PreRender( CViewSetup *pSetup )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::PostRender()
+{
+ // Let the particle manager simulate things that haven't been simulated.
+ ParticleMgr()->PostRender();
+}
+
+void ClientModeShared::PostRenderVGui()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::Update()
+{
+#if defined( REPLAY_ENABLED )
+ UpdateReplayMessages();
+#endif
+
+ if ( m_pViewport->IsVisible() != cl_drawhud.GetBool() )
+ {
+ m_pViewport->SetVisible( cl_drawhud.GetBool() );
+ }
+
+ UpdateRumbleEffects();
+
+ if ( cl_show_num_particle_systems.GetBool() )
+ {
+ int nCount = 0;
+
+ for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
+ {
+ const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
+ CParticleSystemDefinition *pParticleSystem = g_pParticleSystemMgr->FindParticleSystem( pParticleSystemName );
+ if ( !pParticleSystem )
+ continue;
+
+ for ( CParticleCollection *pCurCollection = pParticleSystem->FirstCollection();
+ pCurCollection != NULL;
+ pCurCollection = pCurCollection->GetNextCollectionUsingSameDef() )
+ {
+ ++nCount;
+ }
+ }
+
+ engine->Con_NPrintf( 0, "# Active particle systems: %i", nCount );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// This processes all input before SV Move messages are sent
+//-----------------------------------------------------------------------------
+
+void ClientModeShared::ProcessInput(bool bActive)
+{
+ gHUD.ProcessInput( bActive );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it.
+//-----------------------------------------------------------------------------
+int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ if ( engine->Con_IsVisible() )
+ return 1;
+
+ // Should we start typing a message?
+ if ( pszCurrentBinding &&
+ ( Q_strcmp( pszCurrentBinding, "messagemode" ) == 0 ||
+ Q_strcmp( pszCurrentBinding, "say" ) == 0 ) )
+ {
+ if ( down )
+ {
+ StartMessageMode( MM_SAY );
+ }
+ return 0;
+ }
+ else if ( pszCurrentBinding &&
+ ( Q_strcmp( pszCurrentBinding, "messagemode2" ) == 0 ||
+ Q_strcmp( pszCurrentBinding, "say_team" ) == 0 ) )
+ {
+ if ( down )
+ {
+ StartMessageMode( MM_SAY_TEAM );
+ }
+ return 0;
+ }
+
+ // If we're voting...
+#ifdef VOTING_ENABLED
+ CHudVote *pHudVote = GET_HUDELEMENT( CHudVote );
+ if ( pHudVote && pHudVote->IsVisible() )
+ {
+ if ( !pHudVote->KeyInput( down, keynum, pszCurrentBinding ) )
+ {
+ return 0;
+ }
+ }
+#endif
+
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ // if ingame spectator mode, let spectator input intercept key event here
+ if( pPlayer &&
+ ( pPlayer->GetObserverMode() > OBS_MODE_DEATHCAM ) &&
+ !HandleSpectatorKeyInput( down, keynum, pszCurrentBinding ) )
+ {
+ return 0;
+ }
+
+ // Let game-specific hud elements get a crack at the key input
+ if ( !HudElementKeyInput( down, keynum, pszCurrentBinding ) )
+ {
+ return 0;
+ }
+
+ C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
+ if ( pWeapon )
+ {
+ return pWeapon->KeyInput( down, keynum, pszCurrentBinding );
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if spectator input occurred. Return 0 if the key is swallowed.
+//-----------------------------------------------------------------------------
+int ClientModeShared::HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ // we are in spectator mode, open spectator menu
+ if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+duck" ) == 0 )
+ {
+ m_pViewport->ShowPanel( PANEL_SPECMENU, true );
+ return 0; // we handled it, don't handle twice or send to server
+ }
+ else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack" ) == 0 )
+ {
+ engine->ClientCmd( "spec_next" );
+ return 0;
+ }
+ else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack2" ) == 0 )
+ {
+ engine->ClientCmd( "spec_prev" );
+ return 0;
+ }
+ else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+jump" ) == 0 )
+ {
+ engine->ClientCmd( "spec_mode" );
+ return 0;
+ }
+ else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+strafe" ) == 0 )
+ {
+ HLTVCamera()->SetAutoDirector( true );
+#if defined( REPLAY_ENABLED )
+ ReplayCamera()->SetAutoDirector( true );
+#endif
+ return 0;
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if hud elements want key input. Return 0 if the key is swallowed
+//-----------------------------------------------------------------------------
+int ClientModeShared::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
+{
+ if ( m_pWeaponSelection )
+ {
+ if ( !m_pWeaponSelection->KeyInput( down, keynum, pszCurrentBinding ) )
+ {
+ return 0;
+ }
+ }
+
+#if defined( REPLAY_ENABLED )
+ if ( m_pReplayReminderPanel )
+ {
+ if ( m_pReplayReminderPanel->HudElementKeyInput( down, keynum, pszCurrentBinding ) )
+ {
+ return 0;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool ClientModeShared::DoPostScreenSpaceEffects( const CViewSetup *pSetup )
+{
+#if defined( REPLAY_ENABLED )
+ if ( engine->IsPlayingDemo() )
+ {
+ if ( !replay_rendersetting_renderglow.GetBool() )
+ return false;
+ }
+#endif
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Panel
+//-----------------------------------------------------------------------------
+vgui::Panel *ClientModeShared::GetMessagePanel()
+{
+ if ( m_pChatElement && m_pChatElement->GetInputPanel() && m_pChatElement->GetInputPanel()->IsVisible() )
+ return m_pChatElement->GetInputPanel();
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The player has started to type a message
+//-----------------------------------------------------------------------------
+void ClientModeShared::StartMessageMode( int iMessageModeType )
+{
+ // Can only show chat UI in multiplayer!!!
+ if ( gpGlobals->maxClients == 1 )
+ {
+ return;
+ }
+ if ( m_pChatElement )
+ {
+ m_pChatElement->StartMessageMode( iMessageModeType );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *newmap -
+//-----------------------------------------------------------------------------
+void ClientModeShared::LevelInit( const char *newmap )
+{
+ m_pViewport->GetAnimationController()->StartAnimationSequence("LevelInit");
+
+ // Tell the Chat Interface
+ if ( m_pChatElement )
+ {
+ m_pChatElement->LevelInit( newmap );
+ }
+
+ // we have to fake this event clientside, because clients connect after that
+ IGameEvent *event = gameeventmanager->CreateEvent( "game_newmap" );
+ if ( event )
+ {
+ event->SetString("mapname", newmap );
+ gameeventmanager->FireEventClientSide( event );
+ }
+
+ // Create a vgui context for all of the in-game vgui panels...
+ if ( s_hVGuiContext == DEFAULT_VGUI_CONTEXT )
+ {
+ s_hVGuiContext = vgui::ivgui()->CreateContext();
+ }
+
+ // Reset any player explosion/shock effects
+ CLocalPlayerFilter filter;
+ enginesound->SetPlayerDSP( filter, 0, true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ClientModeShared::LevelShutdown( void )
+{
+ // Reset the third person camera so we don't crash
+ g_ThirdPersonManager.Init();
+
+ if ( m_pChatElement )
+ {
+ m_pChatElement->LevelShutdown();
+ }
+ if ( s_hVGuiContext != DEFAULT_VGUI_CONTEXT )
+ {
+ vgui::ivgui()->DestroyContext( s_hVGuiContext );
+ s_hVGuiContext = DEFAULT_VGUI_CONTEXT;
+ }
+
+ // Reset any player explosion/shock effects
+ CLocalPlayerFilter filter;
+ enginesound->SetPlayerDSP( filter, 0, true );
+}
+
+
+void ClientModeShared::Enable()
+{
+ vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();;
+
+ // Add our viewport to the root panel.
+ if( pRoot != 0 )
+ {
+ m_pViewport->SetParent( pRoot );
+ }
+
+ // All hud elements should be proportional
+ // This sets that flag on the viewport and all child panels
+ m_pViewport->SetProportional( true );
+
+ m_pViewport->SetCursor( m_CursorNone );
+ vgui::surface()->SetCursor( m_CursorNone );
+
+ m_pViewport->SetVisible( true );
+ if ( m_pViewport->IsKeyBoardInputEnabled() )
+ {
+ m_pViewport->RequestFocus();
+ }
+
+ Layout();
+}
+
+
+void ClientModeShared::Disable()
+{
+ vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();;
+
+ // Remove our viewport from the root panel.
+ if( pRoot != 0 )
+ {
+ m_pViewport->SetParent( (vgui::VPANEL)NULL );
+ }
+
+ m_pViewport->SetVisible( false );
+}
+
+
+void ClientModeShared::Layout()
+{
+ vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();
+ int wide, tall;
+
+ // Make the viewport fill the root panel.
+ if( pRoot != 0 )
+ {
+ vgui::ipanel()->GetSize(pRoot, wide, tall);
+
+ bool changed = wide != m_nRootSize[ 0 ] || tall != m_nRootSize[ 1 ];
+ m_nRootSize[ 0 ] = wide;
+ m_nRootSize[ 1 ] = tall;
+
+ m_pViewport->SetBounds(0, 0, wide, tall);
+ if ( changed )
+ {
+ ReloadScheme();
+ }
+ }
+}
+
+float ClientModeShared::GetViewModelFOV( void )
+{
+ return v_viewmodel_fov.GetFloat();
+}
+
+class CHudChat;
+
+bool PlayerNameNotSetYet( const char *pszName )
+{
+ if ( pszName && pszName[0] )
+ {
+ // Don't show "unconnected" if we haven't got the players name yet
+ if ( Q_strnicmp(pszName,"unconnected",11) == 0 )
+ return true;
+ if ( Q_strnicmp(pszName,"NULLNAME",11) == 0 )
+ return true;
+ }
+
+ return false;
+}
+
+void ClientModeShared::FireGameEvent( IGameEvent *event )
+{
+ CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
+
+ const char *eventname = event->GetName();
+
+ if ( Q_strcmp( "player_connect", eventname ) == 0 )
+ {
+ if ( !hudChat )
+ return;
+ if ( PlayerNameNotSetYet(event->GetString("name")) )
+ return;
+
+ if ( !IsInCommentaryMode() )
+ {
+ wchar_t wszLocalized[100];
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("name"), wszPlayerName, sizeof(wszPlayerName) );
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_game" ), 1, wszPlayerName );
+
+ char szLocalized[100];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
+
+ hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized );
+ }
+ }
+ else if ( Q_strcmp( "player_disconnect", eventname ) == 0 )
+ {
+ C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
+
+ if ( !hudChat || !pPlayer )
+ return;
+ if ( PlayerNameNotSetYet(event->GetString("name")) )
+ return;
+
+ if ( !IsInCommentaryMode() )
+ {
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
+
+ wchar_t wszReason[64];
+ const char *pszReason = event->GetString( "reason" );
+ if ( pszReason && ( pszReason[0] == '#' ) && g_pVGuiLocalize->Find( pszReason ) )
+ {
+ V_wcsncpy( wszReason, g_pVGuiLocalize->Find( pszReason ), sizeof( wszReason ) );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode( pszReason, wszReason, sizeof(wszReason) );
+ }
+
+ wchar_t wszLocalized[100];
+ if (IsPC())
+ {
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 2, wszPlayerName, wszReason );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_left_game" ), 1, wszPlayerName );
+ }
+
+ char szLocalized[100];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
+
+ hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized );
+ }
+ }
+ else if ( Q_strcmp( "player_team", eventname ) == 0 )
+ {
+ C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
+ if ( !hudChat )
+ return;
+
+ bool bDisconnected = event->GetBool("disconnect");
+
+ if ( bDisconnected )
+ return;
+
+ int team = event->GetInt( "team" );
+ bool bAutoTeamed = event->GetInt( "autoteam", false );
+ bool bSilent = event->GetInt( "silent", false );
+
+ const char *pszName = event->GetString( "name" );
+ if ( PlayerNameNotSetYet( pszName ) )
+ return;
+
+ if ( !bSilent )
+ {
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( pszName, wszPlayerName, sizeof(wszPlayerName) );
+
+ wchar_t wszTeam[64];
+ C_Team *pTeam = GetGlobalTeam( team );
+ if ( pTeam )
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode( pTeam->Get_Name(), wszTeam, sizeof(wszTeam) );
+ }
+ else
+ {
+ _snwprintf ( wszTeam, sizeof( wszTeam ) / sizeof( wchar_t ), L"%d", team );
+ }
+
+ if ( !IsInCommentaryMode() )
+ {
+ wchar_t wszLocalized[100];
+ if ( bAutoTeamed )
+ {
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_autoteam" ), 2, wszPlayerName, wszTeam );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_team" ), 2, wszPlayerName, wszTeam );
+ }
+
+ char szLocalized[100];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
+
+ hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s", szLocalized );
+ }
+ }
+
+ if ( pPlayer && pPlayer->IsLocalPlayer() )
+ {
+ // that's me
+ pPlayer->TeamChange( team );
+ }
+ }
+ else if ( Q_strcmp( "player_changename", eventname ) == 0 )
+ {
+ if ( !hudChat )
+ return;
+
+ const char *pszOldName = event->GetString("oldname");
+ if ( PlayerNameNotSetYet(pszOldName) )
+ return;
+
+ wchar_t wszOldName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( pszOldName, wszOldName, sizeof(wszOldName) );
+
+ wchar_t wszNewName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString( "newname" ), wszNewName, sizeof(wszNewName) );
+
+ wchar_t wszLocalized[100];
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_changed_name" ), 2, wszOldName, wszNewName );
+
+ char szLocalized[100];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
+
+ hudChat->Printf( CHAT_FILTER_NAMECHANGE, "%s", szLocalized );
+ }
+ else if (Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 )
+ {
+ int team = event->GetInt( "team" );
+
+ bool bValidTeam = false;
+
+ if ( (GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == team) )
+ {
+ bValidTeam = true;
+ }
+
+ //If we're in the spectator team then we should be getting whatever messages the person I'm spectating gets.
+ if ( bValidTeam == false )
+ {
+ CBasePlayer *pSpectatorTarget = UTIL_PlayerByIndex( GetSpectatorTarget() );
+
+ if ( pSpectatorTarget && (GetSpectatorMode() == OBS_MODE_IN_EYE || GetSpectatorMode() == OBS_MODE_CHASE) )
+ {
+ if ( pSpectatorTarget->GetTeamNumber() == team )
+ {
+ bValidTeam = true;
+ }
+ }
+ }
+
+ if ( team == 0 && GetLocalTeam() > 0 )
+ {
+ bValidTeam = false;
+ }
+
+ if ( team == 255 )
+ {
+ bValidTeam = true;
+ }
+
+ if ( bValidTeam == true )
+ {
+ EmitSound_t et;
+ et.m_pSoundName = event->GetString("sound");
+ et.m_nFlags = event->GetInt("additional_flags");
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, et );
+ }
+ }
+ else if ( Q_strcmp( "server_cvar", eventname ) == 0 )
+ {
+ if ( !IsInCommentaryMode() )
+ {
+ wchar_t wszCvarName[64];
+ g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarname"), wszCvarName, sizeof(wszCvarName) );
+
+ wchar_t wszCvarValue[64];
+ g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarvalue"), wszCvarValue, sizeof(wszCvarValue) );
+
+ wchar_t wszLocalized[256];
+ g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_server_cvar_changed" ), 2, wszCvarName, wszCvarValue );
+
+ char szLocalized[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
+
+ hudChat->Printf( CHAT_FILTER_SERVERMSG, "%s", szLocalized );
+ }
+ }
+ else if ( Q_strcmp( "achievement_earned", eventname ) == 0 )
+ {
+ int iPlayerIndex = event->GetInt( "player" );
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
+ int iAchievement = event->GetInt( "achievement" );
+
+ if ( !hudChat || !pPlayer )
+ return;
+
+ if ( !IsInCommentaryMode() )
+ {
+ CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr *>( engine->GetAchievementMgr() );
+ if ( !pAchievementMgr )
+ return;
+
+ IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement );
+ if ( pAchievement )
+ {
+ if ( !pPlayer->IsDormant() && pPlayer->ShouldAnnounceAchievement() )
+ {
+ pPlayer->SetNextAchievementAnnounceTime( gpGlobals->curtime + ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME );
+
+ // no particle effect if the local player is the one with the achievement or the player is dead
+ if ( !pPlayer->IsLocalPlayer() && pPlayer->IsAlive() )
+ {
+ //tagES using the "head" attachment won't work for CS and DoD
+ pPlayer->ParticleProp()->Create( "achieved", PATTACH_POINT_FOLLOW, "head" );
+ }
+
+ pPlayer->OnAchievementAchieved( iAchievement );
+ }
+
+ if ( g_PR )
+ {
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) );
+
+ const wchar_t *pchLocalizedAchievement = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievement->GetName() );
+ if ( pchLocalizedAchievement )
+ {
+ wchar_t wszLocalizedString[128];
+ g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#Achievement_Earned" ), 2, wszPlayerName, pchLocalizedAchievement );
+
+ char szLocalized[128];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) );
+
+ hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized );
+ }
+ }
+ }
+ }
+ }
+#if defined( TF_CLIENT_DLL )
+ else if ( Q_strcmp( "item_found", eventname ) == 0 )
+ {
+ int iPlayerIndex = event->GetInt( "player" );
+ entityquality_t iItemQuality = event->GetInt( "quality" );
+ int iMethod = event->GetInt( "method" );
+ int iItemDef = event->GetInt( "itemdef" );
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
+ const GameItemDefinition_t *pItemDefinition = dynamic_cast<GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( iItemDef ) );
+
+ if ( !pPlayer || !pItemDefinition )
+ return;
+
+ if ( g_PR )
+ {
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) );
+
+ if ( iMethod < 0 || iMethod >= ARRAYSIZE( g_pszItemFoundMethodStrings ) )
+ {
+ iMethod = 0;
+ }
+
+ const char *pszLocString = g_pszItemFoundMethodStrings[iMethod];
+ if ( pszLocString )
+ {
+ wchar_t wszItemFound[256];
+ _snwprintf( wszItemFound, ARRAYSIZE( wszItemFound ), L"%ls", g_pVGuiLocalize->Find( pszLocString ) );
+
+ wchar_t *colorMarker = wcsstr( wszItemFound, L"::" );
+ if ( colorMarker )
+ {
+ const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)iItemQuality );
+ if ( pszQualityColorString )
+ {
+ hudChat->SetCustomColor( pszQualityColorString );
+ *(colorMarker+1) = COLOR_CUSTOM;
+ }
+ }
+
+ // TODO: Update the localization strings to only have two format parameters since that's all we need.
+ wchar_t wszLocalizedString[256];
+ g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItemDefinition, iItemQuality ).GetFullName(), L"" );
+
+ char szLocalized[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) );
+
+ hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized );
+ }
+ }
+ }
+#endif
+#if defined( REPLAY_ENABLED )
+ else if ( !V_strcmp( "replay_servererror", eventname ) )
+ {
+ DisplayReplayMessage( event->GetString( "error", "#Replay_DefaultServerError" ), replay_msgduration_error.GetFloat(), true, NULL, false );
+ }
+ else if ( !V_strcmp( "replay_startrecord", eventname ) )
+ {
+ m_flReplayStartRecordTime = gpGlobals->curtime;
+ }
+ else if ( !V_strcmp( "replay_endrecord", eventname ) )
+ {
+ m_flReplayStopRecordTime = gpGlobals->curtime;
+ }
+ else if ( !V_strcmp( "replay_replaysavailable", eventname ) )
+ {
+ DisplayReplayMessage( "#Replay_ReplaysAvailable", replay_msgduration_replaysavailable.GetFloat(), false, NULL, false );
+ }
+
+ else if ( !V_strcmp( "game_newmap", eventname ) )
+ {
+ // Make sure the instance count is reset to 0. Sometimes the count stay in sync and we get replay messages displaying lower than they should.
+ CReplayMessagePanel::RemoveAll();
+ }
+#endif
+
+ else
+ {
+ DevMsg( 2, "Unhandled GameEvent in ClientModeShared::FireGameEvent - %s\n", event->GetName() );
+ }
+}
+
+void ClientModeShared::UpdateReplayMessages()
+{
+#if defined( REPLAY_ENABLED )
+ // Received a replay_startrecord event?
+ if ( m_flReplayStartRecordTime != 0.0f )
+ {
+ DisplayReplayMessage( "#Replay_StartRecord", replay_msgduration_startrecord.GetFloat(), true, "replay\\startrecord.mp3", false );
+
+ m_flReplayStartRecordTime = 0.0f;
+ m_flReplayStopRecordTime = 0.0f;
+ }
+
+ // Received a replay_endrecord event?
+ if ( m_flReplayStopRecordTime != 0.0f )
+ {
+ DisplayReplayMessage( "#Replay_EndRecord", replay_msgduration_stoprecord.GetFloat(), true, "replay\\stoprecord.wav", false );
+
+ // Hide the replay reminder
+ if ( m_pReplayReminderPanel )
+ {
+ m_pReplayReminderPanel->Hide();
+ }
+
+ m_flReplayStopRecordTime = 0.0f;
+ }
+
+ if ( !engine->IsConnected() )
+ {
+ ClearReplayMessageList();
+ }
+#endif
+}
+
+void ClientModeShared::ClearReplayMessageList()
+{
+#if defined( REPLAY_ENABLED )
+ CReplayMessagePanel::RemoveAll();
+#endif
+}
+
+void ClientModeShared::DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent,
+ const char *pSound, bool bDlg )
+{
+#if defined( REPLAY_ENABLED )
+ // Don't display during replay playback, and don't allow more than 4 at a time
+ const bool bInReplay = g_pEngineClientReplay->IsPlayingReplayDemo();
+ if ( bInReplay || ( !bDlg && CReplayMessagePanel::InstanceCount() >= 4 ) )
+ return;
+
+ // Use default duration?
+ if ( flDuration == -1.0f )
+ {
+ flDuration = replay_msgduration_misc.GetFloat();
+ }
+
+ // Display a replay message
+ if ( bDlg )
+ {
+ if ( engine->IsInGame() )
+ {
+ Panel *pPanel = new CReplayMessageDlg( pLocalizeName );
+ pPanel->SetVisible( true );
+ pPanel->MakePopup();
+ pPanel->MoveToFront();
+ pPanel->SetKeyBoardInputEnabled( true );
+ pPanel->SetMouseInputEnabled( true );
+#if defined( TF_CLIENT_DLL )
+ TFModalStack()->PushModal( pPanel );
+#endif
+ }
+ else
+ {
+ ShowMessageBox( "#Replay_GenericMsgTitle", pLocalizeName, "#GameUI_OK" );
+ }
+ }
+ else
+ {
+ CReplayMessagePanel *pMsgPanel = new CReplayMessagePanel( pLocalizeName, flDuration, bUrgent );
+ pMsgPanel->Show();
+ }
+
+ // Play a sound if appropriate
+ if ( pSound )
+ {
+ surface()->PlaySound( pSound );
+ }
+#endif
+}
+
+void ClientModeShared::DisplayReplayReminder()
+{
+#if defined( REPLAY_ENABLED )
+ if ( m_pReplayReminderPanel && g_pReplay->IsRecording() )
+ {
+ // Only display the panel if we haven't already requested a replay for the given life
+ CReplay *pCurLifeReplay = static_cast< CReplay * >( g_pClientReplayContext->GetReplayManager()->GetReplayForCurrentLife() );
+ if ( pCurLifeReplay && !pCurLifeReplay->m_bRequestedByUser && !pCurLifeReplay->m_bSaved )
+ {
+ m_pReplayReminderPanel->Show();
+ }
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// In-game VGUI context
+//-----------------------------------------------------------------------------
+void ClientModeShared::ActivateInGameVGuiContext( vgui::Panel *pPanel )
+{
+ vgui::ivgui()->AssociatePanelWithContext( s_hVGuiContext, pPanel->GetVPanel() );
+ vgui::ivgui()->ActivateContext( s_hVGuiContext );
+}
+
+void ClientModeShared::DeactivateInGameVGuiContext()
+{
+ vgui::ivgui()->ActivateContext( DEFAULT_VGUI_CONTEXT );
+}
+