From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/client/clientmode_shared.cpp | 1394 ++++++++++++++++++++++++++++++ 1 file changed, 1394 insertions(+) create mode 100644 mp/src/game/client/clientmode_shared.cpp (limited to 'mp/src/game/client/clientmode_shared.cpp') diff --git a/mp/src/game/client/clientmode_shared.cpp b/mp/src/game/client/clientmode_shared.cpp new file mode 100644 index 00000000..31acc934 --- /dev/null +++ b/mp/src/game/client/clientmode_shared.cpp @@ -0,0 +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 +#include +#include +#include +#include "engine/IEngineSound.h" +#include +#include +#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 +#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; iSetString( 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( 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( 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 ); +} + -- cgit v1.2.3