Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3992 lines
132 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include "hud.h"
  10. #include "clientmode_csnormal.h"
  11. #include "cdll_client_int.h"
  12. #include "iinput.h"
  13. #include "vgui/ISystem.h"
  14. #include "vgui/ISurface.h"
  15. #include "vgui/IPanel.h"
  16. #include <vgui_controls/AnimationController.h>
  17. #include "ivmodemanager.h"
  18. #include "buymenu.h"
  19. #include "cliententitylist.h"
  20. #include "filesystem.h"
  21. #include "vgui/IVGui.h"
  22. #include "hud_basechat.h"
  23. #include "view_shared.h"
  24. #include "view.h"
  25. #include "ivrenderview.h"
  26. #if !defined( CSTRIKE15 )
  27. #include "cstrikeclassmenu.h"
  28. #else
  29. #include "cs_gamerules.h"
  30. #include "classmenu.h"
  31. #include "gameui/gameui_interface.h"
  32. #include "c_cs_playerresource.h"
  33. #include "smokegrenade_projectile.h"
  34. #endif //!CSTRIKE15
  35. #include "c_props.h"
  36. #include "c_baseplayer.h"
  37. #include "model_types.h"
  38. #include "iefx.h"
  39. #include "dlight.h"
  40. #include <imapoverview.h>
  41. #include "c_playerresource.h"
  42. #include "c_soundscape.h"
  43. #include <keyvalues.h>
  44. #include "text_message.h"
  45. #include "panelmetaclassmgr.h"
  46. #include "vguicenterprint.h"
  47. #include "physpropclientside.h"
  48. #include "c_weapon__stubs.h"
  49. #include <engine/IEngineSound.h>
  50. #include "c_cs_hostage.h"
  51. #include "buy_presets/buy_presets.h"
  52. #include "bitbuf.h"
  53. #include "usermessages.h"
  54. #include "prediction.h"
  55. #include "datacache/imdlcache.h"
  56. #include "iachievementmgr.h"
  57. #include "achievementmgr.h"
  58. #include "cs_achievementdefs.h"
  59. #include "achievements_cs.h"
  60. #include "hud_macros.h"
  61. #include "c_plantedc4.h"
  62. #include "tier1/fmtstr.h"
  63. #include "history_resource.h"
  64. #include "cs_client_gamestats.h"
  65. #include "viewpostprocess.h"
  66. #include "../../engine/keys.h"
  67. #include "inputsystem/iinputsystem.h"
  68. #include "matchmaking/mm_helpers.h"
  69. #include "gameui/basepanel.h"
  70. #include "gameui/uigamedata.h"
  71. #include "Scaleform/messagebox_scaleform.h"
  72. #include "GameStats.h"
  73. #if defined ( _GAMECONSOLE )
  74. #include "GameUI/IGameUI.h"
  75. #include "GameUI/gameui_interface.h"
  76. #endif
  77. #include "platforminputdevice.h"
  78. #include "glow_outline_effect.h"
  79. #include "hltvcamera.h"
  80. #include "basecsgrenade_projectile.h"
  81. #include "hud_chat.h"
  82. #include "Scaleform/HUD/sfhud_uniquealerts.h"
  83. #include "Scaleform/HUD/sfhud_rosettaselector.h"
  84. #include "hltvreplaysystem.h"
  85. #include "netmessages.h"
  86. #include "playerdecals_signature.h"
  87. #if defined ( _X360 )
  88. #include "ixboxsystem.h"
  89. #endif
  90. // NOTE: This has to be the last file included!
  91. #include "tier0/memdbgon.h"
  92. //
  93. // WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!
  94. //
  95. // PROGRAMMER WARNING: because there are essentially two instances of this class
  96. // in the client.dll (ClientModeCSNormal itself, and ClientModeCSFullscreen : public ClientModeCSNormal)
  97. // this means that both instances of this class will add message hooks of each own that call
  98. // the same global function as the handler. So basically for every single message sent by
  99. // the server your global __MsgFunc_XXX handler will be invoked twice. So make sure that the
  100. // messages and handlers hooked this way are "idempotent" and resilient from being called multiple
  101. // times per each one message generated by the server.
  102. //
  103. bool __MsgFunc_MatchEndConditions( const CCSUsrMsg_MatchEndConditions &msg );
  104. bool __MsgFunc_DisconnectToLobby( const CCSUsrMsg_DisconnectToLobby &msg );
  105. bool __MsgFunc_WarmupHasEnded( const CCSUsrMsg_WarmupHasEnded &msg );
  106. bool __MsgFunc_ServerRankUpdate( const CCSUsrMsg_ServerRankUpdate &msg );
  107. bool __MsgFunc_ServerRankRevealAll( const CCSUsrMsg_ServerRankRevealAll &msg );
  108. bool __MsgFunc_ScoreLeaderboardData( const CCSUsrMsg_ScoreLeaderboardData &msg );
  109. bool __MsgFunc_GlowPropTurnOff( const CCSUsrMsg_GlowPropTurnOff &msg );
  110. bool __MsgFunc_XpUpdate( const CCSUsrMsg_XpUpdate &msg );
  111. bool __MsgFunc_QuestProgress( const CCSUsrMsg_QuestProgress &msg );
  112. bool __MsgFunc_PlayerDecalDigitalSignature( const CCSUsrMsg_PlayerDecalDigitalSignature &msg );
  113. //
  114. // WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!
  115. //
  116. class CHudHintDisplay;
  117. class CHudChat;
  118. //-----------------------------------------------------------------------------
  119. ConVar cl_spec_mode(
  120. "cl_spec_mode",
  121. "0",
  122. FCVAR_USERINFO | FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_SS | FCVAR_SERVER_CAN_EXECUTE,
  123. "Saves the last viewed spectator mode for use next time we start to spectate" );
  124. ConVar cl_draw_only_deathnotices( "cl_draw_only_deathnotices", "0", FCVAR_CHEAT, "For drawing only the crosshair and death notices (used for moviemaking)" );
  125. ConVar cl_radar_square_with_scoreboard( "cl_radar_square_with_scoreboard", "1", FCVAR_ARCHIVE | FCVAR_RELEASE, "If set, the radar will toggle to square when the scoreboard is visible." );
  126. ConVar default_fov( "default_fov", "90", FCVAR_CHEAT );
  127. static IClientMode *g_pClientMode[ MAX_SPLITSCREEN_PLAYERS ];
  128. IClientMode *GetClientMode()
  129. {
  130. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  131. return g_pClientMode[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  132. }
  133. // This is a temporary entity used to render the player's model while drawing the class selection menu.
  134. CHandle<C_BaseAnimatingOverlay> g_ClassImagePlayer; // player
  135. CHandle<C_BaseAnimating> g_ClassImageWeapon; // weapon
  136. STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon );
  137. STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
  138. //-----------------------------------------------------------------------------
  139. // HACK: the detail sway convars are archive, and default to 0. Existing CS:S players thus have no detail
  140. // prop sway. We'll force them to DoD's default values for now. What we really need in the long run is
  141. // a system to apply changes to archived convars' defaults to existing players.
  142. extern ConVar cl_detail_max_sway;
  143. extern ConVar cl_detail_avoid_radius;
  144. extern ConVar cl_detail_avoid_force;
  145. extern ConVar cl_detail_avoid_recover_speed;
  146. extern CAchievementMgr g_AchievementMgrCS;
  147. // Player sprays data
  148. struct PlayerSprayClientRequestData_t
  149. {
  150. uint32 m_nEquipSlot;
  151. uint32 m_nDefIdx;
  152. uint32 m_unTintID;
  153. float m_flCreationTime;
  154. };
  155. static uint64 s_flLastDigitalSignatureTime = 0;
  156. static CUtlMap< int, PlayerSprayClientRequestData_t, int, CDefLess< int > > s_mapClientDigitalSignatureRequests;
  157. //--------------------------------------------------------------------------------------------------------
  158. CON_COMMAND_F( cl_reloadpostprocessparams, "", FCVAR_CHEAT )
  159. {
  160. // get optional filename
  161. if ( args.ArgC() == 2 )
  162. {
  163. GetClientModeCSNormal()->LoadPostProcessParamsFromFile( args[1] );
  164. }
  165. else
  166. {
  167. GetClientModeCSNormal()->LoadPostProcessParamsFromFile();
  168. }
  169. }
  170. CON_COMMAND_F( cl_sos_test_set_opvar, "", FCVAR_CHEAT )
  171. {
  172. // get optional filename
  173. if ( args.ArgC() > 2 )
  174. {
  175. engine->SOSSetOpvarFloat( args[1], Q_atof( args[2] ));
  176. }
  177. }
  178. CON_COMMAND_F( cl_sos_test_get_opvar, "", FCVAR_CHEAT )
  179. {
  180. // get optional filename
  181. if ( args.ArgC() > 2 )
  182. {
  183. float flResult;
  184. engine->SOSGetOpvarFloat( args[1], flResult );
  185. DevMsg( "SOS: GetOpvar %s, %f\n", args[1], flResult );
  186. }
  187. }
  188. #if defined( _PS3 )
  189. CON_COMMAND( cl_write_ps3_bindings, "Used internally for scaleform to tell us to write out our bindings to the title data." )
  190. {
  191. if ( args.ArgC() != 3 )
  192. {
  193. ConMsg( "Usage: cl_write_ps3_bindings <controller index> <device ID>\n" );
  194. return;
  195. }
  196. int iController = atoi( args[1] );
  197. int iDeviceID = atoi( args[2] );
  198. GetClientModeCSNormal()->SyncCurrentKeyBindingsToDeviceTitleData( iController, iDeviceID, KEYBINDING_WRITE_TO_TITLEDATA );
  199. }
  200. CON_COMMAND( cl_read_ps3_bindings, "Used internally for scaleform to tell us to read in our bindings from the title data." )
  201. {
  202. if ( args.ArgC() != 3 )
  203. {
  204. ConMsg( "Usage: cl_read_ps3_bindings <controller index> <device ID>\n" );
  205. return;
  206. }
  207. int iController = atoi( args[1] );
  208. int iDeviceID = atoi( args[2] );
  209. GetClientModeCSNormal()->SyncCurrentKeyBindingsToDeviceTitleData( iController, iDeviceID, KEYBINDING_READ_FROM_TITLEDATA );
  210. }
  211. CON_COMMAND( cl_reset_ps3_bindings, "Used internally for scaleform to tell us to reset our bindings to their defaults and save them." )
  212. {
  213. if ( args.ArgC() != 3 )
  214. {
  215. ConMsg( "Usage: cl_reset_ps3_bindings <controller index> <device ID(s) ORed together or -1 for all devices>\n" );
  216. return;
  217. }
  218. int iController = atoi( args[1] );
  219. int iDevicesToReset = atoi( args[2] );
  220. if ( -1 == iDevicesToReset )
  221. {
  222. iDevicesToReset = (int) PlatformInputDevice::GetValidInputDevicesForPlatform();
  223. }
  224. int numDevices = PlatformInputDevice::GetInputDeviceCountforPlatform();
  225. for ( int ii=1; ii<=numDevices; ++ii )
  226. {
  227. InputDevice_t eDevice = PlatformInputDevice::GetInputDeviceTypefromPlatformOrdinal( ii );
  228. // See if we're supposed to reset this particular device.
  229. if ( ( iDevicesToReset & eDevice ) == 0 ) continue;
  230. char *cmdBuffer = NULL;
  231. switch ( eDevice )
  232. {
  233. case INPUT_DEVICE_GAMEPAD:
  234. cmdBuffer = "exec controller_bindings" PLATFORM_EXT ".cfg game\n";
  235. break;
  236. case INPUT_DEVICE_PLAYSTATION_MOVE:
  237. cmdBuffer = "exec controller_move_bindings" PLATFORM_EXT ".cfg game\n";
  238. break;
  239. case INPUT_DEVICE_SHARPSHOOTER:
  240. cmdBuffer = "exec controller_sharp_shooter_bindings" PLATFORM_EXT ".cfg game\n";
  241. break;
  242. }
  243. if ( NULL != cmdBuffer )
  244. {
  245. // Save out the settings for each device.
  246. engine->ExecuteClientCmd( cmdBuffer );
  247. // Need to use another command to write the settings because these commands are deferred.
  248. engine->ExecuteClientCmd( VarArgs( "cl_write_ps3_bindings %d %d", iController, (int)eDevice ) );
  249. }
  250. }
  251. #if defined( _PS3 )
  252. // We need to restore our settings based on our active device since we may have loaded other settings by entering this function.
  253. InputDevice_t currentDevice = g_pInputSystem->GetCurrentInputDevice();
  254. if( currentDevice != INPUT_DEVICE_NONE )
  255. {
  256. // Load the bindings for the specific device.
  257. engine->ExecuteClientCmd( VarArgs( "cl_read_ps3_bindings %d %d", GET_ACTIVE_SPLITSCREEN_SLOT(), (int)currentDevice ) );
  258. }
  259. #endif // _PS3
  260. }
  261. #endif // _PS3
  262. CON_COMMAND_F( toggleRdrOpt, "", FCVAR_DEVELOPMENTONLY )
  263. {
  264. static bool s_fastMode = false;
  265. s_fastMode = !s_fastMode;
  266. if ( s_fastMode )
  267. {
  268. engine->ExecuteClientCmd( "r_csm_fast_path 1" );
  269. engine->ExecuteClientCmd( "r_renderoverlaybatch 1" );
  270. engine->ExecuteClientCmd( "cl_radar_fast_transforms 1" );
  271. #if defined( _WIN32 ) || defined( LINUX )
  272. engine->ExecuteClientCmd( "mat_vtxlit_new_path 1" );
  273. engine->ExecuteClientCmd( "mat_depthwrite_new_path 1" );
  274. engine->ExecuteClientCmd( "mat_lmap_new_path 1" );
  275. engine->ExecuteClientCmd( "mat_unlit_new_path 1" );
  276. #endif
  277. engine->ExecuteClientCmd( "r_2PassBuildDraw 1");
  278. engine->ExecuteClientCmd( "r_threaded_buildWRlist 1");
  279. }
  280. else
  281. {
  282. engine->ExecuteClientCmd( "r_csm_fast_path 0" );
  283. engine->ExecuteClientCmd( "r_renderoverlaybatch 0" );
  284. engine->ExecuteClientCmd( "cl_radar_fast_transforms 0" );
  285. #if defined( _WIN32 ) || defined( LINUX )
  286. engine->ExecuteClientCmd( "mat_vtxlit_new_path 0" );
  287. engine->ExecuteClientCmd( "mat_depthwrite_new_path 0" );
  288. engine->ExecuteClientCmd( "mat_lmap_new_path 0" );
  289. engine->ExecuteClientCmd( "mat_unlit_new_path 0" );
  290. #endif
  291. engine->ExecuteClientCmd( "r_2PassBuildDraw 0");
  292. engine->ExecuteClientCmd( "r_threaded_buildWRlist 0");
  293. }
  294. Msg( "Rdr opt = %s\n", s_fastMode ? "TRUE":"FALSE" );
  295. }
  296. //--------------------------------------------------------------------------------------------------------
  297. const char* ClientModeCSNormal::ms_postProcessEffectNames[NUM_POST_EFFECTS] =
  298. {
  299. "default",
  300. "low_health",
  301. "very_low_health",
  302. "in_buy_menu",
  303. "death_cam",
  304. "spectating",
  305. "in_fire",
  306. "zoomed_rifle",
  307. "zoomed_sniper",
  308. "zoomed_sniper_moving",
  309. "under_water",
  310. "round_end_via_bombing",
  311. "spec_camera_lerping",
  312. "map_control_unused",
  313. "death_cam_bodyshot",
  314. "death_cam_headshot"
  315. };
  316. //--------------------------------------------------------------------------------------------------------
  317. PostProcessParameters_t ClientModeCSNormal::ms_postProcessParams[NUM_POST_EFFECTS] =
  318. {
  319. //{ 0.5f, 0.0f, 0.8f, 1.1f, 0.0f, 0.0f }, // default
  320. //{ 2.5f, 0.0f, 0.8f, 1.1f, 0.0f, 0.0f }, // low_health
  321. //{ 1.8f, -1.0f, 0.6f, 0.95f, 0.0f, 0.0f }, // in_buy_menu
  322. //{ -0.4f, 0.0f, 0.8f, 1.1f, 0.0f, 0.0f }, // death_cam
  323. //{ -0.4f, 0.0f, 0.8f, 1.1f, 0.0f, 0.0f }, // spectating
  324. //{ 1.25f,-.65f, 0.4f, .85f, 0.0f, 0.0f } // in fire
  325. };
  326. //-----------------------------------------------------------------------------
  327. ConVar cl_autobuy(
  328. "cl_autobuy",
  329. "",
  330. FCVAR_RELEASE,
  331. "The order in which autobuy will attempt to purchase items" );
  332. //-----------------------------------------------------------------------------
  333. ConVar cl_rebuy(
  334. "cl_rebuy",
  335. "",
  336. FCVAR_RELEASE,
  337. "The order in which rebuy will attempt to repurchase items" );
  338. //-----------------------------------------------------------------------------
  339. static void SetBuyData( ConVar &buyVar, const char *filename )
  340. {
  341. // if we already have autobuy data, don't bother re-parsing the text file
  342. if ( *buyVar.GetString() )
  343. return;
  344. // read in the auto buy string file and construct the string we will send to the mp.dll.
  345. const char *pfile = (char*)UTIL_LoadFileForMe( filename, NULL );
  346. if (pfile == NULL)
  347. {
  348. return;
  349. }
  350. char token[256] = {};
  351. char buystring[256] = {};
  352. pfile = engine->ParseFile( pfile, token, sizeof(token) );
  353. bool first = true;
  354. while (pfile != NULL)
  355. {
  356. if (first)
  357. {
  358. first = false;
  359. }
  360. else
  361. {
  362. Q_strncat(buystring, " ", sizeof(buystring), COPY_ALL_CHARACTERS);
  363. }
  364. Q_strncat(buystring, token, sizeof(buystring), COPY_ALL_CHARACTERS);
  365. pfile = engine->ParseFile( pfile, token, sizeof(token) );
  366. }
  367. UTIL_FreeFile((byte *)pfile);
  368. buyVar.SetValue( buystring );
  369. }
  370. bool MsgFunc_KillCam( const CCSUsrMsg_KillCam &msg )
  371. {
  372. C_CSPlayer *pPlayer = ToCSPlayer( C_BasePlayer::GetLocalPlayer() );
  373. if ( !pPlayer )
  374. return true;
  375. int newMode = msg.obs_mode();
  376. if ( newMode != g_nKillCamMode )
  377. {
  378. #if !defined( NO_ENTITY_PREDICTION )
  379. if ( g_nKillCamMode == OBS_MODE_NONE )
  380. {
  381. // kill cam is switch on, turn off prediction
  382. g_bForceCLPredictOff = true;
  383. }
  384. else if ( newMode == OBS_MODE_NONE )
  385. {
  386. // kill cam is switched off, restore old prediction setting is we switch back to normal mode
  387. g_bForceCLPredictOff = false;
  388. }
  389. #endif
  390. g_nKillCamMode = newMode;
  391. }
  392. g_nKillCamTarget1 = msg.first_target();
  393. g_nKillCamTarget2 = msg.second_target();
  394. return true;
  395. }
  396. bool MsgFunc_DisplayInventory( const CCSUsrMsg_DisplayInventory &msg )
  397. {
  398. C_CSPlayer *pPlayer = ToCSPlayer( C_BasePlayer::GetLocalPlayer() );
  399. if ( !pPlayer )
  400. return true;
  401. bool showPistol = msg.display();
  402. int nID = msg.user_id();
  403. if ( pPlayer->GetUserID() == nID )
  404. {
  405. pPlayer->DisplayInventory(showPistol);
  406. return true;
  407. }
  408. return false;
  409. }
  410. // --------------------------------------------------------------------------------- //
  411. // CCSModeManager.
  412. // --------------------------------------------------------------------------------- //
  413. class CCSModeManager : public IVModeManager
  414. {
  415. public:
  416. virtual void Init();
  417. virtual void SwitchMode( bool commander, bool force ) {}
  418. virtual void LevelInit( const char *newmap );
  419. virtual void LevelShutdown( void );
  420. virtual void ActivateMouse( bool isactive ) {}
  421. };
  422. static CCSModeManager g_ModeManager;
  423. IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager;
  424. // --------------------------------------------------------------------------------- //
  425. // CCSModeManager implementation.
  426. // --------------------------------------------------------------------------------- //
  427. #define SCREEN_FILE "scripts/vgui_screens.txt"
  428. void CCSModeManager::Init()
  429. {
  430. for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  431. {
  432. ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
  433. g_pClientMode[ i ] = GetClientModeNormal();
  434. }
  435. PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
  436. }
  437. void CCSModeManager::LevelInit( const char *newmap )
  438. {
  439. for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  440. {
  441. ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
  442. GetClientMode()->LevelInit( newmap );
  443. }
  444. SetBuyData( cl_autobuy, "autobuy.txt" );
  445. SetBuyData( cl_rebuy, "rebuy.txt" );
  446. GetClientModeCSNormal()->SetupStaticCameras();
  447. #if !defined( NO_ENTITY_PREDICTION )
  448. if ( g_nKillCamMode > OBS_MODE_NONE )
  449. {
  450. g_bForceCLPredictOff = false;
  451. }
  452. #endif
  453. g_nKillCamMode = OBS_MODE_NONE;
  454. g_nKillCamTarget1 = 0;
  455. g_nKillCamTarget2 = 0;
  456. // HACK: the detail sway convars are archive, and default to 0. Existing CS:S players thus have no detail
  457. // prop sway. We'll force them to DoD's default values for now.
  458. if ( !cl_detail_max_sway.GetFloat() &&
  459. !cl_detail_avoid_radius.GetFloat() &&
  460. !cl_detail_avoid_force.GetFloat() &&
  461. !cl_detail_avoid_recover_speed.GetFloat() )
  462. {
  463. cl_detail_max_sway.SetValue( "5" );
  464. cl_detail_avoid_radius.SetValue( "64" );
  465. cl_detail_avoid_force.SetValue( "0.4" );
  466. cl_detail_avoid_recover_speed.SetValue( "0.25" );
  467. }
  468. // Record a level transition counter
  469. ++ ClientModeCSNormal::s_numLevelTransitions;
  470. }
  471. void CCSModeManager::LevelShutdown( void )
  472. {
  473. for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
  474. {
  475. ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
  476. GetClientMode()->LevelShutdown();
  477. }
  478. }
  479. static void EnableSteamScreenshots( bool bEnable )
  480. {
  481. #if !defined(NO_STEAM)
  482. if ( steamapicontext && steamapicontext->SteamScreenshots() )
  483. {
  484. ConVarRef cl_savescreenshotstosteam( "cl_savescreenshotstosteam" );
  485. if ( cl_savescreenshotstosteam.IsValid() )
  486. {
  487. cl_savescreenshotstosteam.SetValue( bEnable );
  488. steamapicontext->SteamScreenshots()->HookScreenshots( bEnable );
  489. }
  490. }
  491. #endif
  492. }
  493. #if !defined(NO_STEAM)
  494. CON_COMMAND( cl_steamscreenshots, "Enable/disable saving screenshots to Steam" )
  495. {
  496. bool bEnable = true;
  497. if ( args.ArgC() == 2 )
  498. bEnable = atoi(args[1]) ? true : false;
  499. EnableSteamScreenshots( bEnable );
  500. }
  501. #endif
  502. //-----------------------------------------------------------------------------
  503. // Purpose:
  504. //-----------------------------------------------------------------------------
  505. ClientModeCSNormal::ClientModeCSNormal()
  506. {
  507. m_CCKillCamReplay = INVALID_CLIENT_CCHANDLE;
  508. m_CCKillCamReplayPercent = 0;
  509. m_CCDeathHandle = INVALID_CLIENT_CCHANDLE;
  510. m_CCDeathPercent = 0.0f;
  511. m_CCFreezePeriodHandle_CT = INVALID_CLIENT_CCHANDLE;
  512. m_CCFreezePeriodPercent_CT = 0.0f;
  513. m_CCFreezePeriodHandle_T = INVALID_CLIENT_CCHANDLE;
  514. m_CCFreezePeriodPercent_T = 0.0f;
  515. m_CCPlayerFlashedHandle = INVALID_CLIENT_CCHANDLE;
  516. m_CCPlayerFlashedPercent = 0.0f;
  517. m_activePostProcessEffect = POST_EFFECT_DEFAULT;
  518. m_lastPostProcessEffect = POST_EFFECT_DEFAULT;
  519. m_pActivePostProcessController = NULL;
  520. m_postProcessLerpStartParams = ms_postProcessParams[ POST_EFFECT_DEFAULT ];
  521. m_postProcessLerpEndParams = ms_postProcessParams[ POST_EFFECT_DEFAULT ];
  522. m_postProcessCurrentParams = ms_postProcessParams[ POST_EFFECT_DEFAULT ];
  523. m_iRoundStatus = ROUND_UNKNOWN;
  524. m_fDelayedCTWinTime = -1.0f;
  525. m_nRoundMVP = 0;
  526. }
  527. ClientModeCSNormal::~ClientModeCSNormal()
  528. {
  529. }
  530. void ClientModeCSNormal::Init()
  531. {
  532. BaseClass::Init();
  533. g_pMatchFramework->GetEventsSubscription()->Subscribe( this );
  534. ListenForGameEvent( "round_end" );
  535. ListenForGameEvent( "round_mvp" );
  536. ListenForGameEvent( "round_start" );
  537. ListenForGameEvent( "round_time_warning" );
  538. ListenForGameEvent( "cs_round_start_beep" );
  539. ListenForGameEvent( "cs_round_final_beep" );
  540. ListenForGameEvent( "player_team" );
  541. ListenForGameEvent( "player_death" );
  542. ListenForGameEvent( "bomb_planted" );
  543. ListenForGameEvent( "bomb_exploded" );
  544. ListenForGameEvent( "bomb_defused" );
  545. ListenForGameEvent( "hostage_follows" );
  546. ListenForGameEvent( "hostage_killed" );
  547. ListenForGameEvent( "hostage_hurt" );
  548. ListenForGameEvent( "write_game_titledata" );
  549. ListenForGameEvent( "read_game_titledata" );
  550. ListenForGameEvent( "switch_team" );
  551. ListenForGameEvent( "tr_show_finish_msgbox" );
  552. ListenForGameEvent( "tr_show_exit_msgbox" );
  553. ListenForGameEvent( "reset_player_controls" ); // used for demo purposes
  554. ListenForGameEvent( "seasoncoin_levelup" );
  555. ListenForGameEvent( "game_newmap" );
  556. //
  557. // WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!
  558. //
  559. // PROGRAMMER WARNING: because there are essentially two instances of this class
  560. // in the client.dll (ClientModeCSNormal itself, and ClientModeCSFullscreen : public ClientModeCSNormal)
  561. // this means that both instances of this class will add message hooks of each own that call
  562. // the same global function as the handler. So basically for every single message sent by
  563. // the server your global __MsgFunc_XXX handler will be invoked twice. So make sure that the
  564. // messages and handlers hooked this way are "idempotent" and resilient from being called multiple
  565. // times per each one message generated by the server.
  566. //
  567. HOOK_MESSAGE( MatchEndConditions );
  568. HOOK_MESSAGE( DisconnectToLobby );
  569. HOOK_MESSAGE( WarmupHasEnded );
  570. HOOK_MESSAGE( ServerRankUpdate );
  571. HOOK_MESSAGE( ServerRankRevealAll );
  572. HOOK_MESSAGE( ScoreLeaderboardData );
  573. HOOK_MESSAGE( GlowPropTurnOff );
  574. HOOK_MESSAGE( XpUpdate );
  575. HOOK_MESSAGE( QuestProgress );
  576. HOOK_MESSAGE( PlayerDecalDigitalSignature );
  577. //
  578. // WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!!
  579. //
  580. m_UMCMsgKillCam.Bind< CS_UM_KillCam ,CCSUsrMsg_KillCam >( UtlMakeDelegate ( MsgFunc_KillCam ) );
  581. if ( this != GetFullscreenClientMode() )
  582. {
  583. m_UMCMsgDisplayInventory.Bind< CS_UM_DisplayInventory, CCSUsrMsg_DisplayInventory>( UtlMakeDelegate(MsgFunc_DisplayInventory) );
  584. }
  585. CHudElement* hintBox = (CHudElement*)GET_HUDELEMENT( CHudHintDisplay );
  586. if (hintBox)
  587. {
  588. hintBox->RegisterForRenderGroup("hide_for_scoreboard");
  589. hintBox->RegisterForRenderGroup("hide_for_round_panel");
  590. }
  591. #if !defined( INCLUDE_SCALEFORM )
  592. CHudElement* historyResource = (CHudElement*)GET_HUDELEMENT( CHudHistoryResource );
  593. if (historyResource)
  594. {
  595. historyResource->RegisterForRenderGroup("hide_for_scoreboard");
  596. }
  597. #endif
  598. char szName[ MAX_PATH ] = "";
  599. if ( m_CCKillCamReplay == INVALID_CLIENT_CCHANDLE )
  600. {
  601. const char *szRawFile = "materials/correction/cc_deathcamreplay.raw";
  602. V_snprintf( szName, sizeof( szName ), "%s_ss%d", szRawFile, GET_ACTIVE_SPLITSCREEN_SLOT() );
  603. m_CCKillCamReplayPercent = 0.0f;
  604. m_CCKillCamReplay = g_pColorCorrectionMgr->FindColorCorrection( szName );
  605. if ( m_CCKillCamReplay == INVALID_CLIENT_CCHANDLE )
  606. {
  607. m_CCKillCamReplay = g_pColorCorrectionMgr->AddColorCorrection( szName, szRawFile );
  608. }
  609. }
  610. if ( m_CCDeathHandle == INVALID_CLIENT_CCHANDLE )
  611. {
  612. const char *szRawFile = "materials/correction/cc_death.raw";
  613. V_snprintf( szName, sizeof( szName ), "%s_ss%d", szRawFile, GET_ACTIVE_SPLITSCREEN_SLOT() );
  614. m_CCDeathPercent = 0.0f;
  615. m_CCDeathHandle = g_pColorCorrectionMgr->FindColorCorrection( szName );
  616. if ( m_CCDeathHandle == INVALID_CLIENT_CCHANDLE )
  617. {
  618. m_CCDeathHandle = g_pColorCorrectionMgr->AddColorCorrection( szName, szRawFile );
  619. }
  620. }
  621. if ( m_CCFreezePeriodHandle_CT == INVALID_CLIENT_CCHANDLE )
  622. {
  623. const char *szRawFile = "materials/correction/cc_freeze_ct.raw";
  624. V_snprintf( szName, sizeof( szName ), "%s_ss%d", szRawFile, GET_ACTIVE_SPLITSCREEN_SLOT() );
  625. m_CCFreezePeriodPercent_CT = 0.0f;
  626. m_CCFreezePeriodHandle_CT = g_pColorCorrectionMgr->FindColorCorrection( szName );
  627. if ( m_CCFreezePeriodHandle_CT == INVALID_CLIENT_CCHANDLE )
  628. {
  629. m_CCFreezePeriodHandle_CT = g_pColorCorrectionMgr->AddColorCorrection( szName, szRawFile );
  630. }
  631. }
  632. if ( m_CCFreezePeriodHandle_T == INVALID_CLIENT_CCHANDLE )
  633. {
  634. const char *szRawFile = "materials/correction/cc_freeze_t.raw";
  635. V_snprintf( szName, sizeof( szName ), "%s_ss%d", szRawFile, GET_ACTIVE_SPLITSCREEN_SLOT() );
  636. m_CCFreezePeriodPercent_T = 0.0f;
  637. m_CCFreezePeriodHandle_T = g_pColorCorrectionMgr->FindColorCorrection( szName );
  638. if ( m_CCFreezePeriodHandle_T == INVALID_CLIENT_CCHANDLE )
  639. {
  640. m_CCFreezePeriodHandle_T = g_pColorCorrectionMgr->AddColorCorrection( szName, szRawFile );
  641. }
  642. }
  643. // if ( m_CCPlayerFlashedHandle == INVALID_CLIENT_CCHANDLE )
  644. // {
  645. // const char *szRawFile = "materials/correction/cc_flashed.raw";
  646. // V_snprintf( szName, sizeof( szName ), "%s_ss%d", szRawFile, GET_ACTIVE_SPLITSCREEN_SLOT() );
  647. // m_CCPlayerFlashedPercent = 0.0f;
  648. // m_CCPlayerFlashedHandle = g_pColorCorrectionMgr->FindColorCorrection( szName );
  649. // if ( m_CCPlayerFlashedHandle == INVALID_CLIENT_CCHANDLE )
  650. // {
  651. // m_CCPlayerFlashedHandle = g_pColorCorrectionMgr->AddColorCorrection( szName, szRawFile );
  652. // }
  653. // }
  654. /*
  655. int nTimer = static_cast<int>( ceil( pRules->GetRoundRemainingTime() ) );
  656. bool bFreezePeriod = pRules->IsFreezePeriod();
  657. if ( bFreezePeriod )
  658. {
  659. // countdown to the start of the round while we're in freeze period
  660. nTimer = static_cast<int>( ceil( pRules->GetRoundStartTime() - gpGlobals->curtime ) );
  661. }
  662. */
  663. LoadPostProcessParamsFromFile();
  664. m_hCurrentColorCorrection = NULL;
  665. #if !defined(NO_STEAM) && !defined (_PS3)
  666. m_CallbackScreenshotRequested.Register( this, &ClientModeCSNormal::OnScreenshotRequested );
  667. #endif
  668. EnableSteamScreenshots( true );
  669. }
  670. #if !defined(NO_STEAM) && !defined (_PS3)
  671. void ClientModeCSNormal::OnScreenshotRequested( ScreenshotRequested_t *pParam )
  672. {
  673. // Steam has requested a screenshot, act as if the key currently bound to screenshots
  674. // has been pressed (we want tagging and the killcam screenshot behavior if applicable)
  675. KeyInput( 0, BUTTON_CODE_INVALID, "screenshot" );
  676. engine->ClientCmd( "screenshot" );
  677. }
  678. #endif
  679. void ClientModeCSNormal::InitViewport()
  680. {
  681. BaseClass::InitViewport();
  682. m_pViewport = new CounterStrikeViewport();
  683. m_pViewport->Start( gameuifuncs, gameeventmanager );
  684. }
  685. // dgoodenough - fix GCC shortcoming
  686. // PS3_BUILDFIX
  687. // ClientModeCSFullscreen::InitViewport() wants to do
  688. // BaseClass::BaseClass::InitViewport() to bypass the immediate BaseClass,
  689. // And just init the next class below. GCC doesn't grok this, so we have
  690. // to do this explicitly.
  691. void ClientModeCSNormal::InitViewport( bool bOnlyBaseClass )
  692. {
  693. BaseClass::InitViewport();
  694. if ( !bOnlyBaseClass )
  695. {
  696. m_pViewport = new CounterStrikeViewport();
  697. m_pViewport->Start( gameuifuncs, gameeventmanager );
  698. }
  699. }
  700. void ClientModeCSNormal::SetupStaticCameras()
  701. {
  702. m_SpecCameraPositions.RemoveAll();
  703. char szMapName[MAX_MAP_NAME];
  704. Q_FileBase( engine->GetLevelName(), szMapName, sizeof(szMapName) );
  705. Q_strlower( szMapName );
  706. char szFileName[ MAX_PATH ] = "";
  707. V_snprintf( szFileName, sizeof( szFileName ), "maps/%s_cameras.txt", szMapName );
  708. KeyValues *m_pCamKV = new KeyValues( "Cameras" );
  709. if ( m_pCamKV->LoadFromFile( g_pFullFileSystem, szFileName ) )
  710. {
  711. for ( KeyValues *entry = m_pCamKV->GetFirstSubKey(); entry != NULL; entry = entry->GetNextKey() )
  712. {
  713. CUtlVector< char* > coordNum;
  714. V_SplitString( entry->GetString(), " ", coordNum );
  715. if ( coordNum.Count() < 5 )
  716. {
  717. Msg( "Bad coordinate entry in %s (%s). Each entry needs 5 numbers, 'x y z pitch yaw'", szFileName, entry->GetString() );
  718. continue;
  719. }
  720. SpecCameraPosition_t spot;
  721. spot.vecPosition = Vector( atoi(coordNum[0]), atoi(coordNum[1]), atoi(coordNum[2]) );
  722. spot.vecAngles = Vector( atoi(coordNum[3]), atoi(coordNum[4]), 0.0f );
  723. spot.flWeight = 0.0f;
  724. m_SpecCameraPositions.AddToTail( spot );
  725. coordNum.PurgeAndDeleteElements();
  726. }
  727. }
  728. }
  729. int ClientModeCSNormalCameraSortFunction( const SpecCameraPosition_t* entry1, const SpecCameraPosition_t* entry2 )
  730. {
  731. if ( entry1 == NULL )
  732. return 1;
  733. if ( entry2 == NULL )
  734. return -1;
  735. if ( entry1->flWeight < entry2->flWeight )
  736. return 1;
  737. else
  738. return -1;
  739. }
  740. bool ClientModeCSNormal::GetIdealCameraPosForPlayer( int playerindex )
  741. {
  742. CUtlVector<SpecCameraPosition_t> m_IdealCameras;
  743. CCSPlayer* pPlayer = ToCSPlayer( UTIL_PlayerByIndex( playerindex ) );
  744. if ( !pPlayer )
  745. return false;
  746. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  747. if ( !pLocalPlayer )
  748. return false;
  749. for ( int i=0; i<m_SpecCameraPositions.Count(); ++i )
  750. {
  751. // build a list of cameras that can see the target player
  752. Vector vecCam = Vector( m_SpecCameraPositions[i].vecPosition[0], m_SpecCameraPositions[i].vecPosition[1], m_SpecCameraPositions[i].vecPosition[2] );
  753. trace_t tr;
  754. UTIL_TraceLine( pPlayer->EyePosition(), vecCam, MASK_OPAQUE, pPlayer, COLLISION_GROUP_NONE, &tr );
  755. if ( tr.fraction == 1.0f )
  756. {
  757. // build a list of cameras that can see the target player
  758. Vector vecCam = Vector( m_SpecCameraPositions[i].vecPosition[0], m_SpecCameraPositions[i].vecPosition[1], m_SpecCameraPositions[i].vecPosition[2] );
  759. Vector forward;
  760. AngleVectors( QAngle(m_SpecCameraPositions[i].vecAngles[0],m_SpecCameraPositions[i].vecAngles[1],0.0f) , &forward, NULL, NULL );
  761. Vector toAimSpot = pPlayer->EyePosition() - vecCam;
  762. toAimSpot.NormalizeInPlace();
  763. float flCone = DotProduct( toAimSpot, forward );
  764. float flMaxLength = 600;
  765. float flLength = clamp( VectorLength( pPlayer->EyePosition() - vecCam ), 0, flMaxLength );
  766. if ( flCone > 0.6f )
  767. {
  768. // weight by more centered
  769. m_SpecCameraPositions[i].flWeight = (flCone*1.5);
  770. // weight by closer
  771. m_SpecCameraPositions[i].flWeight += ((flMaxLength - flLength)/flMaxLength)*2;
  772. m_IdealCameras.AddToTail( m_SpecCameraPositions[i] );
  773. }
  774. }
  775. }
  776. if ( m_IdealCameras.Count() > 0 )
  777. {
  778. for ( int i=0; i<m_IdealCameras.Count(); ++i )
  779. {
  780. // now find all other entities/players in view
  781. Vector vecCam = Vector( m_IdealCameras[i].vecPosition[0], m_IdealCameras[i].vecPosition[1], m_IdealCameras[i].vecPosition[2] );
  782. Vector vecStartPos = pPlayer->GetAbsOrigin();
  783. Vector vecMinDist = vecStartPos + Vector( -1024.0f, -1024.0f, -256.0f );
  784. Vector vecMaxDist = vecStartPos + Vector( 1024.0f, 1024.0f, 256.0f );
  785. CBaseEntity *pEntList[128];
  786. int count = UTIL_EntitiesInBox( pEntList, ARRAYSIZE(pEntList), vecMinDist, vecMaxDist, 0 );
  787. const int nMaxFocusPoints = 32;
  788. Vector vecFocusPos[nMaxFocusPoints];
  789. int focusCount = 0;
  790. // add the main player's focus into the array
  791. if ( pPlayer )
  792. {
  793. Vector vecDirShooting, vecRight, vecUp;
  794. AngleVectors( pPlayer->GetFinalAimAngle(), &vecDirShooting, &vecRight, &vecUp );
  795. VectorNormalize( vecDirShooting );
  796. Vector vecPlayerShootPos = pPlayer->Weapon_ShootPosition();
  797. Vector vecEnd = vecPlayerShootPos + (vecDirShooting * 600);
  798. trace_t tr; // main enter bullet trace
  799. UTIL_TraceLine( vecPlayerShootPos, vecEnd, MASK_OPAQUE, pPlayer, COLLISION_GROUP_NONE, &tr );
  800. vecFocusPos[0] = vecStartPos;
  801. vecFocusPos[1] = tr.endpos;
  802. focusCount = 2;
  803. }
  804. for ( int j = 0; j < count; j++ )
  805. {
  806. CBaseEntity *pOther = pEntList[j];
  807. if ( focusCount < nMaxFocusPoints && (dynamic_cast<C_CSPlayer*>(pOther) ||
  808. (dynamic_cast<C_WeaponCSBase*>(pOther) && (dynamic_cast<C_WeaponCSBase*>(pOther)->GetWeaponType() == WEAPONTYPE_C4) ) ||
  809. dynamic_cast<C_PlantedC4*>(pOther) ||
  810. dynamic_cast<CBaseCSGrenadeProjectile*>(pOther)) )
  811. {
  812. Vector vecOtherPos = pOther->IsPlayer() ? pOther->EyePosition() : pOther->GetAbsOrigin();
  813. Vector forward;
  814. AngleVectors( QAngle(m_IdealCameras[i].vecAngles[0],m_IdealCameras[i].vecAngles[1],0.0f) , &forward, NULL, NULL );
  815. Vector toAimSpot = pOther->EyePosition() - vecCam;
  816. toAimSpot.NormalizeInPlace();
  817. float flCone = DotProduct( toAimSpot, forward );
  818. if ( VectorLength( pOther->EyePosition() - vecCam ) > 64.0f )
  819. m_IdealCameras[i].flWeight += flCone;
  820. else
  821. m_IdealCameras[i].flWeight -= 100.0f; // player is blocking the camera
  822. if ( flCone > 0.55f )
  823. {
  824. vecFocusPos[focusCount] = pOther->GetAbsOrigin();
  825. focusCount++;
  826. }
  827. }
  828. }
  829. Vector vecAvPos = Vector( 0, 0, 0 );
  830. for ( int j = 0; j < focusCount; j++ )
  831. {
  832. vecAvPos += vecFocusPos[j];
  833. }
  834. Vector vecNewPos = vecStartPos;
  835. if ( focusCount > 0 )
  836. {
  837. vecNewPos = (vecAvPos/focusCount);
  838. }
  839. // look into direction of second target
  840. QAngle cameraAngles;
  841. Vector forward = vecNewPos - vecCam;
  842. VectorAngles( forward, cameraAngles );
  843. // set the stored camera angles to point to the center of the mass of players weighting the selected player
  844. m_IdealCameras[i].vecAngles[0] = cameraAngles[0];
  845. m_IdealCameras[i].vecAngles[1] = cameraAngles[1];
  846. }
  847. if ( m_IdealCameras.Count() > 1 )
  848. m_IdealCameras.Sort( ClientModeCSNormalCameraSortFunction );
  849. int slot = 0;
  850. char commandBuffer[128];
  851. char commandB[32] = "spec_goto";
  852. float flLerpTime = 0.5f;
  853. Vector vecSpecPos = g_bEngineIsHLTV ? HLTVCamera()->GetCameraPosition() : pLocalPlayer->GetAbsOrigin();
  854. trace_t tr;
  855. UTIL_TraceLine( m_IdealCameras[slot].vecPosition, vecSpecPos, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
  856. if ( pLocalPlayer && tr.fraction == 1.0f )
  857. V_snprintf( commandB, sizeof( commandB ), "%s", "spec_lerpto" );
  858. V_snprintf( commandBuffer, sizeof( commandBuffer ), "%s %f %f %f %f %f %d %f", commandB, m_IdealCameras[slot].vecPosition[0], m_IdealCameras[slot].vecPosition[1], m_IdealCameras[slot].vecPosition[2], m_IdealCameras[slot].vecAngles[0], m_IdealCameras[slot].vecAngles[1], playerindex, flLerpTime );
  859. engine->ClientCmd( commandBuffer );
  860. m_IdealCameras.RemoveAll();
  861. return true;
  862. }
  863. return false;
  864. }
  865. //-----------------------------------------------------------------------------
  866. // Purpose:
  867. //-----------------------------------------------------------------------------
  868. void ClientModeCSNormal::LevelShutdown( void )
  869. {
  870. BaseClass::LevelShutdown();
  871. // reset all of the post process effects
  872. m_lastPostProcessEffect = POST_EFFECT_DEFAULT;
  873. m_activePostProcessEffect = POST_EFFECT_DEFAULT;
  874. m_pActivePostProcessController = NULL;
  875. m_postProcessEffectCountdown.Reset();
  876. m_postProcessLerpEndParams = ms_postProcessParams[POST_EFFECT_DEFAULT];
  877. m_postProcessLerpStartParams = ms_postProcessParams[POST_EFFECT_DEFAULT];
  878. m_postProcessCurrentParams = ms_postProcessParams[POST_EFFECT_DEFAULT];
  879. // Unregister all glow boxes here otherwise they would leak
  880. GlowObjectManager().UnregisterAllGlowBoxes();
  881. // Clear out all uncommitted quest progress
  882. sm_mapQuestProgressUncommitted.Purge();
  883. s_ScoreLeaderboardData.Clear();
  884. // Shutdown outstanding player spray signature requests
  885. s_mapClientDigitalSignatureRequests.Purge();
  886. s_flLastDigitalSignatureTime = 0;
  887. // Shutdown decals system
  888. extern void OnPlayerDecalsLevelShutdown();
  889. OnPlayerDecalsLevelShutdown();
  890. // Increment level transitions counter
  891. ++ s_numLevelTransitions;
  892. // Remove any lingering debug overlays, since it's possible they won't get cleaned up automatically later.
  893. // This is in response to anecdotal reports that players can 'mark' the world with showimpacts or grenade trajectories,
  894. // then use them to their advantage on subsequent games played immediately on the same map.
  895. debugoverlay->ClearAllOverlays();
  896. }
  897. uint32 ClientModeCSNormal::s_numLevelTransitions = 0;
  898. void ClientModeCSNormal::Update()
  899. {
  900. BaseClass::Update();
  901. UpdatePostProcessingEffects();
  902. // Update decals system
  903. extern void OnPlayerDecalsUpdate();
  904. OnPlayerDecalsUpdate();
  905. // Override the hud's visibility if this is a logo (like E3 demo) map.
  906. if ( CSGameRules() && CSGameRules()->IsLogoMap() )
  907. m_pViewport->SetVisible( false );
  908. if ( ( m_fDelayedCTWinTime > 0.0f ) && ( gpGlobals->curtime >= m_fDelayedCTWinTime ) )
  909. {
  910. CLocalPlayerFilter filter;
  911. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.CTWin");
  912. m_fDelayedCTWinTime = -1.0f;
  913. }
  914. // halftime music needs a delay thusly
  915. static bool bStartedHalfTimeMusic = false;
  916. static float flHalfTimeStart = 0.0;
  917. if( CSGameRules() && ( CSGameRules()->GetGamePhase() == GAMEPHASE_HALFTIME || CSGameRules()->GetGamePhase() == GAMEPHASE_MATCH_ENDED) )
  918. {
  919. if( !bStartedHalfTimeMusic && gpGlobals->curtime - flHalfTimeStart > 6.5 )
  920. {
  921. bStartedHalfTimeMusic = true;
  922. CSingleUserRecipientFilter filter(C_BasePlayer::GetLocalPlayer());
  923. if( CSGameRules()->GetGamePhase() == GAMEPHASE_HALFTIME )
  924. {
  925. PlayMusicSelection(filter, CSMUSIC_HALFTIME);
  926. }
  927. else if( m_nRoundMVP != 0 )
  928. {
  929. PlayMusicSelection(filter, CSMUSIC_HALFTIME, m_nRoundMVP );
  930. }
  931. }
  932. }
  933. else
  934. {
  935. flHalfTimeStart = gpGlobals->curtime;
  936. bStartedHalfTimeMusic = false;
  937. }
  938. #if defined ( _X360 )
  939. if ( !xboxsystem->IsArcadeTitleUnlocked() )
  940. {
  941. const char *levelName = engine->GetLevelName();
  942. if (levelName && levelName[0] && !engine->IsLevelMainMenuBackground())
  943. {
  944. // verify globals->frametime is not outrageous and subtract from arcade trial timer
  945. SplitScreenConVarRef xbox_arcade_remaining_trial_time("xbox_arcade_remaining_trial_time");
  946. if ( gpGlobals->frametime < 5.0f )
  947. {
  948. float trialTime = xbox_arcade_remaining_trial_time.GetFloat( GET_ACTIVE_SPLITSCREEN_SLOT() );
  949. trialTime -= gpGlobals->frametime;
  950. if ( trialTime < 0.0f )
  951. {
  952. trialTime = 0.0f;
  953. }
  954. xbox_arcade_remaining_trial_time.SetValue( GET_ACTIVE_SPLITSCREEN_SLOT(), trialTime );
  955. }
  956. }
  957. }
  958. #endif
  959. if ( HLTVCamera() )
  960. HLTVCamera()->Update();
  961. //
  962. // Check if client is now eligible to stop demo recording
  963. //
  964. if ( CSGameRules() && CSGameRules()->m_bMarkClientStopRecordAtRoundEnd )
  965. {
  966. char name[ 256 ] = "Cannot stop recording now";
  967. if ( clientdll->CanStopRecordDemo( name, sizeof( name ) ) )
  968. {
  969. CSGameRules()->m_bMarkClientStopRecordAtRoundEnd = false;
  970. engine->ClientCmd_Unrestricted( "stop;\n" );
  971. }
  972. }
  973. //
  974. // Check if quests need chat confirmation
  975. //
  976. for ( uint32 i = sm_mapQuestProgressUncommitted.FirstInorder();
  977. i != sm_mapQuestProgressUncommitted.InvalidIndex();
  978. i = sm_mapQuestProgressUncommitted.NextInorder( i ) )
  979. {
  980. CQuestUncommittedProgress_t &questProgress = sm_mapQuestProgressUncommitted.Element( i );
  981. if ( !questProgress.m_dblNormalPointsProgressTime )
  982. continue;
  983. if ( Plat_FloatTime() - questProgress.m_dblNormalPointsProgressTime < 1.6 )
  984. continue;
  985. questProgress.m_dblNormalPointsProgressTime = 0;
  986. if ( questProgress.m_numNormalPointsProgressBaseline < questProgress.m_numNormalPoints )
  987. {
  988. if ( const CEconQuestDefinition *pQuestDef = GetItemSchema()->GetQuestDefinition( sm_mapQuestProgressUncommitted.Key( i ) ) )
  989. {
  990. uint32 numPointsEarned = questProgress.m_numNormalPoints - questProgress.m_numNormalPointsProgressBaseline;
  991. char const *fmtToken = ( numPointsEarned > 1 ) ? "#quest_uncommitted_points_chat_plural" : "#quest_uncommitted_points_chat_singular";
  992. // Quest string keys
  993. KeyValues *pKVLocalizedQuestStrings = new KeyValues( "LocalizedQuestStrings" );
  994. KeyValues::AutoDelete autodelete( pKVLocalizedQuestStrings );
  995. FOR_EACH_SUBKEY( pQuestDef->GetStringTokens(), keyvalue )
  996. {
  997. pKVLocalizedQuestStrings->SetWString( keyvalue->GetName(), g_pVGuiLocalize->Find( keyvalue->GetString() ) );
  998. }
  999. // Points earned
  1000. wchar_t wchPoints[ 64 ] = {};
  1001. V_snwprintf( wchPoints, ARRAYSIZE( wchPoints ), PRI_S_FOR_WS, V_FormatNumber( numPointsEarned ) );
  1002. pKVLocalizedQuestStrings->SetWString( "points", wchPoints );
  1003. if ( questProgress.m_bIsEventQuest )
  1004. {
  1005. fmtToken = "#quest_uncommitted_points_chat_event";
  1006. wchar_t wchQuestName[ 256 ] = {};
  1007. locchar_t * locShortName = L"";
  1008. locShortName = g_pVGuiLocalize->Find( pQuestDef->GetShortNameLocToken( ) );
  1009. if ( !locShortName )
  1010. {
  1011. locShortName = L"QUEST MISSING SHORT NAME";
  1012. }
  1013. g_pVGuiLocalize->ConstructString( wchQuestName, sizeof( wchQuestName ), locShortName, pKVLocalizedQuestStrings );
  1014. pKVLocalizedQuestStrings->SetWString( "quest_short_name", wchQuestName );
  1015. }
  1016. else
  1017. {
  1018. if ( ( !pQuestDef->GetQuestPoints().Count() || ( pQuestDef->GetQuestPoints().Head() <= 1 ) )
  1019. && ( numPointsEarned == 1 )
  1020. && !questProgress.m_numNormalPointsProgressBaseline ) // Missions requiring a single point to score print a custom string
  1021. fmtToken = "#quest_uncommitted_points_chat_one";
  1022. }
  1023. // Make the message
  1024. wchar_t wchHudMessage[256] = {};
  1025. g_pVGuiLocalize->ConstructString( wchHudMessage, sizeof( wchHudMessage ), fmtToken, pKVLocalizedQuestStrings );
  1026. if ( wchHudMessage[0] )
  1027. {
  1028. if ( CHudChat* pChat = ( CHudChat* )( GetHud( 0 ).FindElement( "CHudChat" ) ) )
  1029. {
  1030. pChat->ChatPrintfW( 0, CHAT_FILTER_NONE, wchHudMessage );
  1031. }
  1032. }
  1033. // Quest notification alert
  1034. if (SFUniqueAlerts* pAlerts = (SFUniqueAlerts*)(GetHud(0).FindElement("SFUniqueAlerts")))
  1035. {
  1036. // REI: Not sure this is correct. Need to understand why this is a vector, and which "points" from the
  1037. // vector the uncommitted quest progress is referring to
  1038. const CCopyableUtlVector< uint32 >& questPointsVec = pQuestDef->GetQuestPoints();
  1039. uint32 questPoints = 0;
  1040. if (questPointsVec.Count() > 0)
  1041. questPoints = questPointsVec[0];
  1042. pAlerts->ShowQuestProgress(numPointsEarned, questProgress.m_numNormalPoints, questPoints, "weapon_knife", "do the thing"); // TODO: Correctly extract the weapon icon to use
  1043. }
  1044. }
  1045. }
  1046. questProgress.m_numNormalPointsProgressBaseline = questProgress.m_numNormalPoints;
  1047. }
  1048. // Check if we need anti-addiction chat print out
  1049. static double s_dblLastAntiAddictionCheckPlatFloatTime = 0;
  1050. static int s_nLastTimePlayedConsecutivelyPrinted = 0;
  1051. double dblTimeNow = Plat_FloatTime();
  1052. if ( dblTimeNow > s_dblLastAntiAddictionCheckPlatFloatTime + 50 )
  1053. {
  1054. s_dblLastAntiAddictionCheckPlatFloatTime = dblTimeNow;
  1055. int nTimePlayedConsecutively = 0;//Helper_GetTimePlayedConsecutively();
  1056. if ( ( nTimePlayedConsecutively >= 3600 ) && ( nTimePlayedConsecutively/1200 != s_nLastTimePlayedConsecutivelyPrinted/1200 ) )
  1057. { // Print in chat after 1 hour of anti-addiction consecutive time every 20 minutes
  1058. if ( CHudChat* pChat = ( CHudChat* ) ( GetHud( 0 ).FindElement( "CHudChat" ) ) )
  1059. {
  1060. s_nLastTimePlayedConsecutivelyPrinted = nTimePlayedConsecutively;
  1061. static wchar_t const * const kwszHour = g_pVGuiLocalize->Find( "#SFUI_Warning_AntiAddiction_Time_Hour" );
  1062. static wchar_t const * const kwszHours = g_pVGuiLocalize->Find( "#SFUI_Warning_AntiAddiction_Time_Hours" );
  1063. static wchar_t const * const kwszMinutes = g_pVGuiLocalize->Find( "#SFUI_Warning_AntiAddiction_Time_Minutes" );
  1064. static wchar_t const * const kwszFmtH = g_pVGuiLocalize->Find( "#SFUI_Warning_AntiAddiction_Time_Format_H" );
  1065. static wchar_t const * const kwszFmtHM = g_pVGuiLocalize->Find( "#SFUI_Warning_AntiAddiction_Time_Format_HM" );
  1066. wchar_t wszHours[64] = {}, wszMinutes[64] = {};
  1067. V_swprintf_safe( wszHours, L"%d", nTimePlayedConsecutively/3600 );
  1068. V_swprintf_safe( wszMinutes, L"%02d", ( nTimePlayedConsecutively%3600 ) / 60 );
  1069. wchar_t const *wszFmtTime = ( ( nTimePlayedConsecutively%3600 ) / 60 >= 5 ) ? kwszFmtHM : kwszFmtH;
  1070. wchar_t wszTimeString[256] = {};
  1071. g_pVGuiLocalize->ConstructString( wszTimeString, sizeof( wszTimeString ), wszFmtTime, 4,
  1072. wszHours, ( nTimePlayedConsecutively/3600 > 1 ) ? kwszHours : kwszHour, wszMinutes, kwszMinutes );
  1073. char const *szColor = "Green";
  1074. if ( nTimePlayedConsecutively/3600 >= 5 )
  1075. szColor = "Red";
  1076. else if ( nTimePlayedConsecutively/3600 >= 3 )
  1077. szColor = "Yellow";
  1078. wchar_t wszLocalizedAntiAddiction[1024] = {};
  1079. g_pVGuiLocalize->ConstructString( wszLocalizedAntiAddiction, sizeof( wszLocalizedAntiAddiction ), g_pVGuiLocalize->Find( CFmtStr( "#SFUI_Warning_AntiAddiction_%s", szColor ) ), 1, wszTimeString );
  1080. pChat->ChatPrintfW( 0, CHAT_FILTER_NONE, wszLocalizedAntiAddiction );
  1081. }
  1082. }
  1083. }
  1084. }
  1085. #ifdef _DEBUG
  1086. CON_COMMAND_F(quest_ui_test, "Test quest ui", FCVAR_CLIENTCMD_CAN_EXECUTE)
  1087. {
  1088. int newPoints = 1;
  1089. int totalPoints = 10;
  1090. int maxPoints = 20;
  1091. if (args.ArgC() > 1)
  1092. {
  1093. newPoints = Q_atoi(args.ArgV()[1]);
  1094. }
  1095. if (args.ArgC() > 2)
  1096. {
  1097. totalPoints = Q_atoi(args.ArgV()[2]);
  1098. }
  1099. if (args.ArgC() > 3)
  1100. {
  1101. maxPoints = Q_atoi(args.ArgV()[3]);
  1102. }
  1103. if (SFUniqueAlerts* pAlerts = (SFUniqueAlerts*)(GetHud(0).FindElement("SFUniqueAlerts")))
  1104. {
  1105. pAlerts->ShowQuestProgress(newPoints, totalPoints, maxPoints, "weapon_knife", "quest desc");
  1106. }
  1107. }
  1108. #endif
  1109. ConVar spec_replay_colorcorrection( "spec_replay_colorcorrection", "0.5", FCVAR_CLIENTDLL, "Amount of color correction in deathcam replay" );
  1110. //--------------------------------------------------------------------------------------------------------
  1111. void ClientModeCSNormal::UpdateColorCorrectionWeights( void )
  1112. {
  1113. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1114. C_CSPlayer* pPlayer = ToCSPlayer(pLocalPlayer);
  1115. if ( !pPlayer )
  1116. {
  1117. m_CCKillCamReplayPercent = 0.0f;
  1118. m_CCDeathPercent = 0.0f;
  1119. m_CCFreezePeriodPercent_CT = 0.0f;
  1120. m_CCFreezePeriodPercent_T = 0.0f;
  1121. m_CCPlayerFlashedPercent = 0.0f;
  1122. return;
  1123. }
  1124. m_CCPlayerFlashedPercent = Min( 1.0f, pPlayer->m_flFlashOverlayAlpha + 0.25f );
  1125. if ( g_HltvReplaySystem.GetHltvReplayDelay() )
  1126. {
  1127. m_CCKillCamReplayPercent = spec_replay_colorcorrection.GetFloat();
  1128. m_CCDeathPercent = 0.0f;
  1129. m_CCPlayerFlashedPercent *= 0.5f;
  1130. }
  1131. else
  1132. {
  1133. m_CCKillCamReplayPercent = 0.0f;
  1134. bool isDying = false;
  1135. if ( !pPlayer->IsAlive() && (pPlayer->GetObserverMode() == OBS_MODE_DEATHCAM) )
  1136. {
  1137. isDying = true;
  1138. }
  1139. m_CCDeathPercent = clamp( m_CCDeathPercent + ((isDying) ? 0.1f : -0.1f), 0.0f, 1.0f );
  1140. }
  1141. float flTimer = 0;
  1142. bool bFreezePeriod = CSGameRules()->IsFreezePeriod();
  1143. bool bImmune = pPlayer->m_bGunGameImmunity;
  1144. if ( bFreezePeriod || bImmune )
  1145. {
  1146. float flFadeBegin = 2.0f;
  1147. // countdown to the start of the round while we're in freeze period
  1148. if ( bImmune )
  1149. {
  1150. // if freeze time is also active and freeze time is longer than immune time, use that time instead
  1151. if ( bFreezePeriod && (CSGameRules()->GetRoundStartTime() - gpGlobals->curtime) > (pPlayer->m_fImmuneToGunGameDamageTime - gpGlobals->curtime))
  1152. flTimer = CSGameRules()->GetRoundStartTime() - gpGlobals->curtime;
  1153. else
  1154. {
  1155. flTimer = pPlayer->m_fImmuneToGunGameDamageTime - gpGlobals->curtime;
  1156. flFadeBegin = 0.5;
  1157. }
  1158. }
  1159. else if ( bFreezePeriod )
  1160. {
  1161. flTimer = CSGameRules()->GetRoundStartTime() - gpGlobals->curtime;
  1162. }
  1163. if ( flTimer > flFadeBegin )
  1164. {
  1165. if ( pPlayer->GetTeamNumber() == TEAM_CT )
  1166. {
  1167. m_CCFreezePeriodPercent_CT = 1.0f;
  1168. m_CCFreezePeriodPercent_T = 0.0f;
  1169. }
  1170. else
  1171. {
  1172. m_CCFreezePeriodPercent_CT = 0.0f;
  1173. m_CCFreezePeriodPercent_T = 1.0f;
  1174. }
  1175. }
  1176. else
  1177. {
  1178. if ( pPlayer->GetTeamNumber() == TEAM_CT )
  1179. {
  1180. m_CCFreezePeriodPercent_CT = clamp( flTimer / flFadeBegin, 0.05f, 1.0f );
  1181. m_CCFreezePeriodPercent_T = 0;
  1182. }
  1183. else
  1184. {
  1185. m_CCFreezePeriodPercent_T = clamp( flTimer / flFadeBegin, 0.05f, 1.0f );
  1186. m_CCFreezePeriodPercent_CT = 0;
  1187. }
  1188. }
  1189. }
  1190. else
  1191. {
  1192. int nTeam = CSGameRules()->IsHostageRescueMap() ? TEAM_TERRORIST : TEAM_CT;
  1193. if ( CSGameRules()->IsPlayingCooperativeGametype() && pPlayer->GetTeamNumber() == nTeam )
  1194. {
  1195. m_CCFreezePeriodPercent_T = 0;
  1196. m_CCFreezePeriodPercent_CT = MIN( 1.0f, pPlayer->m_flGuardianTooFarDistFrac * 3);
  1197. }
  1198. else
  1199. {
  1200. m_CCFreezePeriodPercent_T = 0;
  1201. m_CCFreezePeriodPercent_CT = 0;
  1202. }
  1203. }
  1204. }
  1205. void ClientModeCSNormal::OnColorCorrectionWeightsReset( void )
  1206. {
  1207. UpdateColorCorrectionWeights();
  1208. g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCKillCamReplay, m_CCKillCamReplayPercent );
  1209. g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCDeathHandle, m_CCDeathPercent );
  1210. g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCFreezePeriodHandle_CT, m_CCFreezePeriodPercent_CT );
  1211. g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCFreezePeriodHandle_T, m_CCFreezePeriodPercent_T );
  1212. g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCPlayerFlashedHandle, m_CCPlayerFlashedPercent );
  1213. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1214. if ( pPlayer )
  1215. {
  1216. C_ColorCorrection* pCC = pPlayer->GetActiveColorCorrection();
  1217. if ( pCC != m_hCurrentColorCorrection )
  1218. {
  1219. if ( m_hCurrentColorCorrection )
  1220. {
  1221. m_hCurrentColorCorrection->EnableOnClient( false );
  1222. }
  1223. if ( pCC )
  1224. {
  1225. pCC->EnableOnClient( true, m_hCurrentColorCorrection == NULL );
  1226. }
  1227. m_hCurrentColorCorrection = pCC;
  1228. }
  1229. }
  1230. }
  1231. float ClientModeCSNormal::GetColorCorrectionScale( void ) const
  1232. {
  1233. return 1.0f;
  1234. }
  1235. //--------------------------------------------------------------------------------------------------------
  1236. PostProcessEffect_t ClientModeCSNormal::PostProcessEffectFromName( const char* pName ) const
  1237. {
  1238. for ( int i = 0; i < NUM_POST_EFFECTS; i++ )
  1239. {
  1240. if ( V_stricmp( pName, ms_postProcessEffectNames[i] ) == 0 )
  1241. {
  1242. return PostProcessEffect_t( i );
  1243. }
  1244. }
  1245. return NUM_POST_EFFECTS;
  1246. }
  1247. //--------------------------------------------------------------------------------------------------------
  1248. void ClientModeCSNormal::LoadPostProcessParamsFromFile( const char* pFileName )
  1249. {
  1250. if ( !pFileName )
  1251. {
  1252. pFileName = "scripts/postprocess.txt";
  1253. }
  1254. KeyValues *pPPKeys = new KeyValues( "post_process" );
  1255. if ( pPPKeys->LoadFromFile( g_pFullFileSystem, pFileName ) == false )
  1256. {
  1257. Warning( "Error loading postprocessing params from file %s\n" , pFileName );
  1258. pPPKeys->deleteThis();
  1259. return;
  1260. }
  1261. for ( KeyValues* pSubKeys = pPPKeys->GetFirstTrueSubKey(); pSubKeys; pSubKeys = pSubKeys->GetNextTrueSubKey() )
  1262. {
  1263. PostProcessEffect_t effect = PostProcessEffectFromName( pSubKeys->GetName() );
  1264. if ( effect == NUM_POST_EFFECTS )
  1265. {
  1266. Warning( "Unknown postprocess effect type: %s\n", pSubKeys->GetName() );
  1267. continue;
  1268. }
  1269. ms_postProcessParams[effect].m_flParameters[PPPN_FADE_TIME] = pSubKeys->GetFloat( "fadetime", 0.5f );
  1270. ms_postProcessParams[effect].m_flParameters[PPPN_LOCAL_CONTRAST_STRENGTH] = pSubKeys->GetFloat( "localcontrast", 0.0f );
  1271. ms_postProcessParams[effect].m_flParameters[PPPN_LOCAL_CONTRAST_EDGE_STRENGTH] = pSubKeys->GetFloat( "edgelocalcontrast", 0.0f );
  1272. ms_postProcessParams[effect].m_flParameters[PPPN_VIGNETTE_START] = pSubKeys->GetFloat( "vignettestart", 1.0f );
  1273. ms_postProcessParams[effect].m_flParameters[PPPN_VIGNETTE_END] = pSubKeys->GetFloat( "vignetteend", 2.0f );
  1274. ms_postProcessParams[effect].m_flParameters[PPPN_VIGNETTE_BLUR_STRENGTH] = pSubKeys->GetFloat( "vignetteblur", 0.0f );
  1275. ms_postProcessParams[effect].m_flParameters[PPPN_FADE_TO_BLACK_STRENGTH] = pSubKeys->GetFloat( "fadetoblack", 0.0f );
  1276. ms_postProcessParams[effect].m_flParameters[PPPN_DEPTH_BLUR_FOCAL_DISTANCE] = pSubKeys->GetFloat( "depthblur_focaldist", 0.0f );
  1277. ms_postProcessParams[effect].m_flParameters[PPPN_DEPTH_BLUR_STRENGTH] = pSubKeys->GetFloat( "depthblur_strength", 0.0f );
  1278. ms_postProcessParams[effect].m_flParameters[PPPN_SCREEN_BLUR_STRENGTH] = pSubKeys->GetFloat( "screenblur_strength", 0.0f );
  1279. ms_postProcessParams[effect].m_flParameters[PPPN_FILM_GRAIN_STRENGTH] = pSubKeys->GetFloat( "filmgrain_strength", 0.0f );
  1280. }
  1281. // update the currently active postprocess type with the new params
  1282. if ( m_activePostProcessEffect < NUM_POST_EFFECTS )
  1283. {
  1284. m_postProcessLerpEndParams = ms_postProcessParams[m_activePostProcessEffect];
  1285. }
  1286. pPPKeys->deleteThis();
  1287. }
  1288. //--------------------------------------------------------------------------------------------------------
  1289. void ClientModeCSNormal::UpdatePostProcessingEffects()
  1290. {
  1291. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1292. C_CSPlayer* pPlayer = ToCSPlayer(pLocalPlayer);
  1293. // If we set off the bomb, run the bomb round end post process effect.
  1294. if ( pPlayer && m_iRoundStatus == ROUND_ENDED_VIA_BOMBING && (pPlayer->GetObserverMode() == OBS_MODE_DEATHCAM || ( pPlayer->GetObserverTarget() && !pPlayer->GetObserverTarget()->IsPlayer() ) ) )
  1295. {
  1296. PostProcessLerpTo( POST_EFFECT_ROUND_END_VIA_BOMBING, 1.0f );
  1297. }
  1298. else if ( !pPlayer )
  1299. {
  1300. PostProcessLerpTo( POST_EFFECT_DEFAULT );
  1301. }
  1302. else if ( pPlayer->GetViewEntity() != NULL )
  1303. {
  1304. // Our view is on a camera
  1305. PostProcessLerpTo( POST_EFFECT_DEFAULT );
  1306. }
  1307. else if ( pPlayer->GetObserverInterpState() == C_CSPlayer::OBSERVER_INTERP_TRAVELING )
  1308. {
  1309. PostProcessLerpTo( POST_EFFECT_SPEC_CAMERA_LERPING, 0.1f );
  1310. }
  1311. else if ( pPlayer->IsBuyMenuOpen() )
  1312. {
  1313. PostProcessLerpTo( POST_EFFECT_IN_BUY_MENU, 0.1f );
  1314. }
  1315. else if ( false ) // [msmith]: Currently in progress...
  1316. {
  1317. PostProcessLerpTo( POST_EFFECT_UNDER_WATER, 0.1f );
  1318. }
  1319. else if ( pPlayer->IsAlive() && pPlayer->GetFOV() != pPlayer->GetDefaultFOV() && pPlayer->m_bIsScoped )
  1320. {
  1321. CWeaponCSBase *pWeapon = pPlayer->GetActiveCSWeapon();
  1322. if ( pWeapon && pWeapon->GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE )
  1323. {
  1324. float flBaseAccuracy = pWeapon->GetInaccuracyStand();
  1325. float flInacc = MAX( pWeapon->GetInaccuracy() - flBaseAccuracy, 0 );
  1326. if ( flInacc * 100 > 5 )
  1327. PostProcessLerpTo( POST_EFFECT_ZOOMED_SNIPER_MOVING, 0.01f );
  1328. else
  1329. PostProcessLerpTo( POST_EFFECT_ZOOMED_SNIPER, 0.01f );
  1330. }
  1331. else if ( pWeapon )
  1332. {
  1333. PostProcessLerpTo( POST_EFFECT_ZOOMED_RIFLE, 0.01f );
  1334. }
  1335. }
  1336. else if ( !pPlayer->IsAlive() && pPlayer->m_iDeathPostEffect > 0 && mp_forcecamera.GetInt() != OBS_ALLOW_ALL )
  1337. {
  1338. PostProcessEffect_t post_effect = ( PostProcessEffect_t ) pPlayer->m_iDeathPostEffect;
  1339. if ( post_effect == POST_EFFECT_DEATH_CAM_BODYSHOT )
  1340. {
  1341. extern ConVar spec_freeze_time;
  1342. PostProcessLerpTo( POST_EFFECT_DEATH_CAM_BODYSHOT, spec_freeze_time.GetInt() );
  1343. }
  1344. else if ( post_effect == POST_EFFECT_DEATH_CAM_HEADSHOT )
  1345. {
  1346. PostProcessLerpTo( POST_EFFECT_DEATH_CAM_HEADSHOT, 1.0f );
  1347. }
  1348. }
  1349. else if ( !pPlayer->IsAlive() && pPlayer->GetObserverTarget() == NULL && pPlayer->GetObserverMode() == OBS_MODE_DEATHCAM )
  1350. {
  1351. PostProcessLerpTo( POST_EFFECT_DEATH_CAM );
  1352. }
  1353. /*
  1354. else if ( pPlayer && pPlayer->GetHealth() <= pPlayer->GetMaxHealth()/3 )
  1355. {
  1356. float flStartHealthFrac = (pPlayer->GetMaxHealth()/3) * 0.01;
  1357. float fHealthFrac = clamp( (float)pPlayer->GetHealth() / (float)pPlayer->GetMaxHealth(), 0.0f, 1.0f );
  1358. float flFXFrac = fHealthFrac / flStartHealthFrac;
  1359. PostProcessParameters_t incapParams;
  1360. // lerp target params based on health state, then let DoPostProcessParamLerp() do the rest
  1361. LerpPostProcessParam( 1.0f - flFXFrac, incapParams, ms_postProcessParams[POST_EFFECT_LOW_HEATH], ms_postProcessParams[POST_EFFECT_VERY_LOW_HEATH] );
  1362. PostProcessLerpTo( POST_EFFECT_DEFAULT, 0.5f, &incapParams );
  1363. }
  1364. else if ( pPlayer->GetEffectEntity() != NULL )
  1365. {
  1366. PostProcessLerpTo( POST_EFFECT_IN_FIRE );
  1367. }*/
  1368. else
  1369. {
  1370. C_PostProcessController* pPPCtrl = pPlayer->GetActivePostProcessController();
  1371. float flFadeTime = 0.5f;
  1372. if ( m_activePostProcessEffect == POST_EFFECT_ZOOMED_SNIPER_MOVING || m_activePostProcessEffect == POST_EFFECT_ZOOMED_SNIPER ||
  1373. m_activePostProcessEffect == POST_EFFECT_ZOOMED_RIFLE )
  1374. {
  1375. flFadeTime = 0.0f;
  1376. }
  1377. else if ( m_activePostProcessEffect == POST_EFFECT_SPEC_CAMERA_LERPING )
  1378. {
  1379. flFadeTime = 0.1f;
  1380. }
  1381. else if ( !pPPCtrl && engine->IsLevelMainMenuBackground() )
  1382. {
  1383. // FIXME: In the main menu the server is unable to set up the postprocess controller for the player for some reason.
  1384. // Just use the master controller for now.
  1385. pPPCtrl = C_PostProcessController::GetMasterController();
  1386. }
  1387. if ( !pPPCtrl )
  1388. {
  1389. PostProcessLerpTo( POST_EFFECT_DEFAULT, flFadeTime);
  1390. }
  1391. else
  1392. {
  1393. PostProcessLerpTo( POST_EFFECT_MAP_CONTROLLED, pPPCtrl );
  1394. }
  1395. }
  1396. DoPostProcessParamLerp();
  1397. // Apply params to postprocessing code
  1398. PostProcessParameters_t currentParams = m_postProcessCurrentParams;
  1399. SetPostProcessParams( &currentParams );
  1400. }
  1401. //--------------------------------------------------------------------------------------------------------
  1402. void ClientModeCSNormal::PostProcessLerpTo( PostProcessEffect_t effectID, float fFadeDuration, const PostProcessParameters_t* pTargetParams )
  1403. {
  1404. if ( m_activePostProcessEffect == effectID )
  1405. {
  1406. // the target params might still be updated
  1407. if ( pTargetParams )
  1408. {
  1409. m_postProcessLerpEndParams = *pTargetParams;
  1410. }
  1411. return;
  1412. }
  1413. m_lastPostProcessEffect = m_activePostProcessEffect;
  1414. m_activePostProcessEffect = effectID;
  1415. m_pActivePostProcessController = NULL;
  1416. m_postProcessEffectCountdown.Start( fFadeDuration );
  1417. m_postProcessLerpStartParams = m_postProcessCurrentParams;
  1418. if ( pTargetParams )
  1419. {
  1420. m_postProcessLerpEndParams = *pTargetParams;
  1421. }
  1422. else
  1423. {
  1424. m_postProcessLerpEndParams = ms_postProcessParams[ effectID ];
  1425. }
  1426. }
  1427. //--------------------------------------------------------------------------------------------------------
  1428. void ClientModeCSNormal::PostProcessLerpTo( PostProcessEffect_t effectID, const C_PostProcessController* pPostProcessController )
  1429. {
  1430. Assert( pPostProcessController );
  1431. m_lastPostProcessEffect = m_activePostProcessEffect;
  1432. m_activePostProcessEffect = effectID;
  1433. if ( m_pActivePostProcessController != pPostProcessController )
  1434. {
  1435. float flFade = pPostProcessController->m_PostProcessParameters.m_flParameters[PPPN_FADE_TIME];
  1436. // we force the fade back time to be short when coming from the buy menu
  1437. if ( m_lastPostProcessEffect == POST_EFFECT_IN_BUY_MENU )
  1438. flFade = 0.25;
  1439. else if ( m_lastPostProcessEffect == POST_EFFECT_ZOOMED_RIFLE || m_lastPostProcessEffect == POST_EFFECT_ZOOMED_SNIPER || m_lastPostProcessEffect == POST_EFFECT_ZOOMED_SNIPER_MOVING )
  1440. flFade = 0.01;
  1441. else if ( m_lastPostProcessEffect == POST_EFFECT_SPEC_CAMERA_LERPING )
  1442. flFade = 0.1;
  1443. else if ( m_lastPostProcessEffect == POST_EFFECT_DEATH_CAM_BODYSHOT || m_lastPostProcessEffect == POST_EFFECT_DEATH_CAM_HEADSHOT )
  1444. flFade = 0.01;
  1445. m_pActivePostProcessController = pPostProcessController;
  1446. m_postProcessEffectCountdown.Start( flFade );
  1447. m_postProcessLerpStartParams = m_postProcessCurrentParams;
  1448. }
  1449. m_postProcessLerpEndParams = pPostProcessController->m_PostProcessParameters;
  1450. }
  1451. //--------------------------------------------------------------------------------------------------------
  1452. void ClientModeCSNormal::DoPostProcessParamLerp()
  1453. {
  1454. float fAmount = 1.0f - m_postProcessEffectCountdown.GetRemainingRatio();
  1455. // just force it
  1456. if ( fAmount == 1 )
  1457. m_postProcessCurrentParams = m_postProcessLerpEndParams;
  1458. else
  1459. {
  1460. #define PP_LERP(x) m_postProcessCurrentParams.x = Lerp( fAmount, m_postProcessLerpStartParams.x, m_postProcessLerpEndParams.x )
  1461. PP_LERP( m_flParameters[PPPN_FADE_TO_BLACK_STRENGTH] );
  1462. PP_LERP( m_flParameters[PPPN_LOCAL_CONTRAST_EDGE_STRENGTH] );
  1463. PP_LERP( m_flParameters[PPPN_LOCAL_CONTRAST_STRENGTH] );
  1464. PP_LERP( m_flParameters[PPPN_VIGNETTE_BLUR_STRENGTH] );
  1465. PP_LERP( m_flParameters[PPPN_VIGNETTE_END] );
  1466. PP_LERP( m_flParameters[PPPN_VIGNETTE_START] );
  1467. PP_LERP( m_flParameters[PPPN_DEPTH_BLUR_FOCAL_DISTANCE] );
  1468. PP_LERP( m_flParameters[PPPN_DEPTH_BLUR_STRENGTH] );
  1469. PP_LERP( m_flParameters[PPPN_SCREEN_BLUR_STRENGTH] );
  1470. PP_LERP( m_flParameters[PPPN_FILM_GRAIN_STRENGTH] );
  1471. #undef PP_LERP
  1472. }
  1473. }
  1474. //--------------------------------------------------------------------------------------------------------
  1475. void ClientModeCSNormal::LerpPostProcessParam( float fAmount, PostProcessParameters_t& result, const PostProcessParameters_t& from,
  1476. const PostProcessParameters_t& to ) const
  1477. {
  1478. #define PP_LERP(x) result.x = Lerp( fAmount, from.x, to.x )
  1479. PP_LERP( m_flParameters[PPPN_FADE_TO_BLACK_STRENGTH] );
  1480. PP_LERP( m_flParameters[PPPN_LOCAL_CONTRAST_EDGE_STRENGTH] );
  1481. PP_LERP( m_flParameters[PPPN_LOCAL_CONTRAST_STRENGTH] );
  1482. PP_LERP( m_flParameters[PPPN_VIGNETTE_BLUR_STRENGTH] );
  1483. PP_LERP( m_flParameters[PPPN_VIGNETTE_END] );
  1484. PP_LERP( m_flParameters[PPPN_VIGNETTE_START] );
  1485. PP_LERP( m_flParameters[PPPN_DEPTH_BLUR_FOCAL_DISTANCE] );
  1486. PP_LERP( m_flParameters[PPPN_DEPTH_BLUR_STRENGTH] );
  1487. PP_LERP( m_flParameters[PPPN_SCREEN_BLUR_STRENGTH] );
  1488. PP_LERP( m_flParameters[PPPN_FILM_GRAIN_STRENGTH] );
  1489. #undef PP_LERP
  1490. }
  1491. //--------------------------------------------------------------------------------------------------------
  1492. void ClientModeCSNormal::GetDefaultPostProcessingParams( C_CSPlayer* pPlayer, PostProcessEffectParams_t* pParams )
  1493. {
  1494. Assert( pParams );
  1495. C_PostProcessController* pPPCtrl = NULL;
  1496. if ( pPlayer )
  1497. {
  1498. pPPCtrl = pPlayer->GetActivePostProcessController();
  1499. }
  1500. if ( pPPCtrl )
  1501. {
  1502. pParams->fLocalContrastStrength = pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_LOCAL_CONTRAST_STRENGTH];
  1503. pParams->fLocalContrastEdgeStrength = pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_LOCAL_CONTRAST_EDGE_STRENGTH];
  1504. pParams->fVignetteStart = pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_VIGNETTE_START];
  1505. pParams->fVignetteEnd = pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_VIGNETTE_END];
  1506. pParams->fVignetteBlurStrength = pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_VIGNETTE_BLUR_STRENGTH];
  1507. pParams->fFadeToBlackStrength= pPPCtrl->m_PostProcessParameters.m_flParameters[PPPN_FADE_TO_BLACK_STRENGTH];
  1508. }
  1509. else
  1510. {
  1511. memcpy( pParams, &ms_postProcessParams[ POST_EFFECT_DEFAULT ], sizeof( PostProcessEffectParams_t ) );
  1512. }
  1513. }
  1514. /*
  1515. void ClientModeCSNormal::UpdateSpectatorMode( void )
  1516. {
  1517. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1518. if ( !pPlayer )
  1519. return;
  1520. IMapOverview * overviewmap = m_pViewport->GetMapOverviewInterface();
  1521. if ( !overviewmap )
  1522. return;
  1523. overviewmap->SetTime( gpGlobals->curtime );
  1524. int obs_mode = pPlayer->GetObserverMode();
  1525. if ( obs_mode < OBS_MODE_IN_EYE )
  1526. return;
  1527. Vector worldpos = pPlayer->GetLocalOrigin();
  1528. QAngle angles; engine->GetViewAngles( angles );
  1529. C_BaseEntity *target = pPlayer->GetObserverTarget();
  1530. if ( target && (obs_mode == OBS_MODE_IN_EYE || obs_mode == OBS_MODE_CHASE) )
  1531. {
  1532. worldpos = target->GetAbsOrigin();
  1533. if ( obs_mode == OBS_MODE_IN_EYE )
  1534. {
  1535. angles = target->GetAbsAngles();
  1536. }
  1537. }
  1538. Vector2D mappos = overviewmap->WorldToMap( worldpos );
  1539. overviewmap->SetCenter( mappos );
  1540. overviewmap->SetAngle( angles.y );
  1541. for ( int i = 1; i<= MAX_PLAYERS; i++)
  1542. {
  1543. C_BaseEntity *ent = ClientEntityList().GetEnt( i );
  1544. if ( !ent || !ent->IsPlayer() )
  1545. continue;
  1546. C_BasePlayer *p = ToBasePlayer( ent );
  1547. // update position of active players in our PVS
  1548. Vector position = p->GetAbsOrigin();
  1549. QAngle angle = p->GetAbsAngles();
  1550. if ( p->IsDormant() )
  1551. {
  1552. // if player is not in PVS, use PlayerResources data
  1553. position = g_PR->GetPosition( i );
  1554. angles[1] = g_PR->GetViewAngle( i );
  1555. }
  1556. overviewmap->SetPlayerPositions( i-1, position, angles );
  1557. }
  1558. } */
  1559. // Sets convars to tag the current mapname and the player in your crosshairs.
  1560. // The player tagged will be overridden for killcam shots to be the killer
  1561. static void ScreenshotTaggingKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
  1562. {
  1563. if ( pszCurrentBinding && ( FStrEq( pszCurrentBinding, "screenshot" ) || FStrEq( pszCurrentBinding, "jpeg" ) ) )
  1564. {
  1565. // Tag the player in the crosshairs
  1566. C_CSPlayer *pPlayer = ToCSPlayer( C_BasePlayer::GetLocalPlayer() );
  1567. if ( pPlayer )
  1568. {
  1569. C_CSPlayer *pCrosshairs = ToCSPlayer( UTIL_PlayerByIndex( pPlayer->GetIDTarget() ) );
  1570. if ( pCrosshairs && !pCrosshairs->IsBot() )
  1571. {
  1572. CSteamID steamID;
  1573. if ( pCrosshairs->GetSteamID( &steamID ) && steamID.IsValid() )
  1574. {
  1575. ConVarRef cl_screenshotusertag( "cl_screenshotusertag" );
  1576. if ( cl_screenshotusertag.IsValid() )
  1577. {
  1578. cl_screenshotusertag.SetValue( (int)steamID.GetAccountID() );
  1579. }
  1580. }
  1581. }
  1582. }
  1583. // Tag the current map
  1584. ConVarRef cl_screenshotlocation( "cl_screenshotlocation" );
  1585. if ( cl_screenshotlocation.IsValid() )
  1586. {
  1587. char szMapName[MAX_MAP_NAME];
  1588. Q_FileBase( engine->GetLevelName(), szMapName, sizeof(szMapName) );
  1589. Q_strlower( szMapName );
  1590. cl_screenshotlocation.SetValue( szMapName );
  1591. }
  1592. }
  1593. }
  1594. ConVar cl_scoreboard_mouse_enable_binding( "cl_scoreboard_mouse_enable_binding", "+attack2", FCVAR_ARCHIVE, "Name of the binding to enable mouse selection in the scoreboard" );
  1595. //-----------------------------------------------------------------------------
  1596. // Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it.
  1597. //-----------------------------------------------------------------------------
  1598. int ClientModeCSNormal::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
  1599. {
  1600. // don't process input in LogoMaps
  1601. if( CSGameRules() && CSGameRules()->IsLogoMap() )
  1602. return 1;
  1603. // Applies basic tags if we're going to take a screenshot
  1604. ScreenshotTaggingKeyInput( down, keynum, pszCurrentBinding );
  1605. return BaseClass::KeyInput( down, keynum, pszCurrentBinding );
  1606. }
  1607. //-----------------------------------------------------------------------------
  1608. // Purpose: this is the viewport that contains all the hud elements
  1609. //-----------------------------------------------------------------------------
  1610. class CHudViewport : public CBaseViewport
  1611. {
  1612. private:
  1613. DECLARE_CLASS_SIMPLE( CHudViewport, CBaseViewport );
  1614. protected:
  1615. virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
  1616. {
  1617. BaseClass::ApplySchemeSettings( pScheme );
  1618. GetHud().InitColors( pScheme );
  1619. SetPaintBackgroundEnabled( false );
  1620. }
  1621. virtual void CreateDefaultPanels( void ) { /* don't create any panels yet*/ };
  1622. };
  1623. //--------------------------------------------------------------------------------------------------------
  1624. class FullscreenCSViewport : public CHudViewport
  1625. {
  1626. private:
  1627. DECLARE_CLASS_SIMPLE( FullscreenCSViewport, CHudViewport );
  1628. private:
  1629. virtual void InitViewportSingletons( void )
  1630. {
  1631. SetAsFullscreenViewportInterface();
  1632. }
  1633. virtual void SetUpPopup( void )
  1634. {
  1635. }
  1636. virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
  1637. {
  1638. BaseClass::ApplySchemeSettings( pScheme );
  1639. SetMouseInputEnabled( false );
  1640. SetKeyBoardInputEnabled( false );
  1641. }
  1642. };
  1643. class ClientModeCSFullscreen : public ClientModeCSNormal
  1644. {
  1645. DECLARE_CLASS_SIMPLE( ClientModeCSFullscreen, ClientModeCSNormal );
  1646. public:
  1647. virtual void InitViewport()
  1648. {
  1649. // dgoodenough - fix up GCC shortcoming.
  1650. // PS3_BUILDFIX
  1651. // FIXME - there may be a way to do this more elegantly under GCC, but for now,
  1652. // just write a second ClientModeCSNormal::InitViewport(); that takes a bool
  1653. // parameter that allows skipping the init on the immediate BaseClass
  1654. // Skip over BaseClass!!!
  1655. //BaseClass::BaseClass::InitViewport();
  1656. BaseClass::InitViewport( true );
  1657. //BaseClass::InitViewport( );
  1658. m_pViewport = new FullscreenCSViewport();
  1659. m_pViewport->Start( gameuifuncs, gameeventmanager );
  1660. }
  1661. virtual void Init( void );
  1662. virtual void OnEvent( KeyValues *pEvent );
  1663. virtual void FireGameEvent( IGameEvent *event );
  1664. } g_ClientModeFullscreen;
  1665. IClientMode *GetFullscreenClientMode()
  1666. {
  1667. return &g_ClientModeFullscreen;
  1668. }
  1669. ClientModeCSNormal g_ClientModeNormal[ MAX_SPLITSCREEN_PLAYERS ];
  1670. IClientMode *GetClientModeNormal()
  1671. {
  1672. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1673. return &g_ClientModeNormal[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  1674. }
  1675. ClientModeCSNormal* GetClientModeCSNormal()
  1676. {
  1677. return assert_cast< ClientModeCSNormal* >( GetClientModeNormal() );
  1678. }
  1679. int ClientModeCSNormal::GetDeathMessageStartHeight( void )
  1680. {
  1681. return m_pViewport->GetDeathMessageStartHeight();
  1682. }
  1683. void ClientModeCSNormal::SyncCurrentKeyBindingsToDeviceTitleData( int iController, int eDevice, const SyncKeyBindingValueDirection_t eOp )
  1684. {
  1685. #if defined( _GAMECONSOLE )
  1686. #define MAX_BINDING_NAME 64
  1687. //Key Names
  1688. #define ACTION( name )
  1689. #define BINDING( name, cppType ) { #name },
  1690. static char sJoystickNames[][MAX_BINDING_NAME] = {
  1691. #include "xlast_csgo/inc_bindings_usr.inc"
  1692. // Additional Keyboard Bindings for PS3
  1693. #if defined( _PS3 )
  1694. #include "xlast_csgo/inc_ps3_key_bindings_usr.inc"
  1695. #endif
  1696. { "" }
  1697. };
  1698. #undef BINDING
  1699. #undef ACTION
  1700. //Action Names
  1701. #define BINDING( name, cppType )
  1702. #define ACTION( name ) { #name },
  1703. static char sBindingActionNames[][MAX_BINDING_NAME] = {
  1704. #include "xlast_csgo/inc_bindings_usr.inc"
  1705. { "" }
  1706. };
  1707. #undef BINDING
  1708. #undef ACTION
  1709. // Get the number of keybindings.
  1710. static int sNumBindings = 0;
  1711. if ( sNumBindings == 0 )
  1712. {
  1713. while ( sBindingActionNames[sNumBindings][0] != '\0') sNumBindings++;
  1714. }
  1715. // Sync the device specific convars as well.
  1716. #define CFG( name, scfgType, cppType ) { #name },
  1717. static const char sDeviceSpecificSettings[][MAX_BINDING_NAME] = {
  1718. #include "xlast_csgo/inc_gameconsole_device_specific_settings_usr.inc"
  1719. #undef CFG
  1720. { "" }
  1721. };
  1722. static int sNumDeviceSpecificSettings = 0;
  1723. if ( sNumDeviceSpecificSettings == 0 )
  1724. {
  1725. while ( sDeviceSpecificSettings[sNumDeviceSpecificSettings][0] != '\0') sNumDeviceSpecificSettings++;
  1726. }
  1727. // Only process this if it is the controller associated with this clientmodenormal
  1728. #ifndef SPLIT_SCREEN_STUBS
  1729. int iSlot = XBX_GetSlotByUserId( iController );
  1730. ACTIVE_SPLITSCREEN_PLAYER_GUARD( iSlot );
  1731. #endif
  1732. if ( this != GetClientModeCSNormal() )
  1733. return;
  1734. // get the matchmaking local player
  1735. IPlayerLocal *pPlayerLocal = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController );
  1736. if ( !pPlayerLocal )
  1737. return;
  1738. TitleDataFieldsDescription_t const *pFields = g_pMatchFramework->GetMatchTitle()->DescribeTitleDataStorage();
  1739. if ( !pFields )
  1740. return;
  1741. #if defined ( _X360 )
  1742. // Check version number
  1743. ConVarRef cl_titledataversionblock3 ( "cl_titledataversionblock3" );
  1744. TitleDataFieldsDescription_t const *versionField = TitleDataFieldsDescriptionFindByString( pFields, "TITLEDATA.BLOCK3.VERSION" );
  1745. if ( !versionField || versionField->m_eDataType != TitleDataFieldsDescription_t::DT_uint16 )
  1746. {
  1747. Warning( "ClientModeCSNormal::SyncCurrentKeyBindingsToDeviceTitleData TITLEDATA.BLOCK3.VERSION is expected to be defined as DT_uint16\n" );
  1748. return;
  1749. }
  1750. if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1751. {
  1752. // If we're reading from title data, check the version to make sure it's good. If not, we bail and just use the defaults that were put into the controls earlier.
  1753. int versionNumber = TitleDataFieldsDescriptionGetValue<uint16>( versionField, pPlayerLocal );
  1754. if ( versionNumber != cl_titledataversionblock3.GetInt() )
  1755. {
  1756. Warning ( "ClientModeCSNormal::SyncCurrentKeyBindingsToDeviceTitleData wrong version # for TITLEDATA.BLOCK3.VERSION; expected %d, got %d\n", cl_titledataversionblock3.GetInt(), versionNumber );
  1757. return;
  1758. }
  1759. }
  1760. else if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1761. {
  1762. // If we're saving, just write the version out.
  1763. TitleDataFieldsDescriptionSetValue<uint16>( versionField, pPlayerLocal, cl_titledataversionblock3.GetInt() );
  1764. }
  1765. #endif // _X360
  1766. char* devicePrefix = "";
  1767. #if defined( _PS3 )
  1768. // For PS3, we have 3 different sets of controller bindings.
  1769. // We want to work on the active controller when reading or writing them out.
  1770. // If we're using the primary controller, then we use an empty string as the text string option.
  1771. switch ( eDevice )
  1772. {
  1773. case INPUT_DEVICE_KEYBOARD_MOUSE:
  1774. case INPUT_DEVICE_GAMEPAD:
  1775. break;
  1776. case INPUT_DEVICE_PLAYSTATION_MOVE:
  1777. devicePrefix = TITLE_DATA_DEVICE_MOVE_PREFIX;
  1778. break;
  1779. case INPUT_DEVICE_SHARPSHOOTER:
  1780. devicePrefix = TITLE_DATA_DEVICE_SHARP_SHOOTER_PREFIX;
  1781. break;
  1782. }
  1783. #endif // _PS3
  1784. char bindingKeyName[MAX_BINDING_NAME];
  1785. if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1786. {
  1787. for (int i=0; sJoystickNames[i][0] != '\0'; ++i)
  1788. {
  1789. Q_snprintf( bindingKeyName, MAX_BINDING_NAME, TITLE_DATA_PREFIX "%sBINDING.%s", devicePrefix, &sJoystickNames[i][0] );
  1790. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( pFields, bindingKeyName );
  1791. if ( NULL == pField )
  1792. {
  1793. Warning( "Could not find TitleDataField for %s\n", bindingKeyName );
  1794. continue;
  1795. }
  1796. if ( pField->m_eDataType != TitleDataFieldsDescription_t::DT_uint8 )
  1797. {
  1798. Warning( "%s is expected to be defined as DT_uint8\n", bindingKeyName );
  1799. continue;
  1800. }
  1801. const char *pBindingName = "";
  1802. uint8 bindingIndex = TitleDataFieldsDescriptionGetValue<uint8>( pField, pPlayerLocal );
  1803. if ( bindingIndex > 0 && bindingIndex < sNumBindings && sBindingActionNames[bindingIndex][0] != '\0' )
  1804. {
  1805. pBindingName = sBindingActionNames[bindingIndex];
  1806. }
  1807. // If the name of the button code is prefixed with "KEY_" then this is a PS3 key binding. Do the direct translation
  1808. // from key name to ButtonCode_t here.
  1809. ButtonCode_t buttonCode = g_pInputSystem->StringToButtonCode( &sJoystickNames[i][0] );
  1810. if ( buttonCode == BUTTON_CODE_INVALID )
  1811. {
  1812. Warning( "ClientModeCSNormal::SyncCurrentKeyBindingsToDeviceTitleData Unknown joystick name %s\n", &sJoystickNames[i][0] );
  1813. }
  1814. else
  1815. {
  1816. engine->Key_SetBinding( buttonCode, pBindingName );
  1817. }
  1818. }
  1819. }
  1820. else if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1821. {
  1822. for (int i=0; sJoystickNames[i][0] != '\0'; ++i)
  1823. {
  1824. Q_snprintf( bindingKeyName, MAX_BINDING_NAME, TITLE_DATA_PREFIX "%sBINDING.%s", devicePrefix, &sJoystickNames[i][0] );
  1825. // find the current binding for the keyname
  1826. ButtonCode_t buttonCode = g_pInputSystem->StringToButtonCode( &sJoystickNames[i][0] );
  1827. const char* keyBinding = engine->Key_BindingForKey( buttonCode );
  1828. if ( NULL == keyBinding )
  1829. continue;
  1830. size_t cmpSize = strlen( keyBinding );
  1831. // Find the keybinding index
  1832. uint8 bindingIndex = 0;
  1833. for ( ; keyBinding && bindingIndex < sNumBindings; ++bindingIndex )
  1834. {
  1835. if ( sBindingActionNames[bindingIndex][0] == '\0' )
  1836. continue;
  1837. if ( cmpSize != strlen( sBindingActionNames[bindingIndex] ) )
  1838. continue;
  1839. if ( !Q_strncmp( &sBindingActionNames[bindingIndex][0], keyBinding, cmpSize ) )
  1840. break;
  1841. }
  1842. if ( bindingIndex == sNumBindings )
  1843. {
  1844. bindingIndex = 0;
  1845. }
  1846. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( pFields, bindingKeyName );
  1847. if ( NULL == pField )
  1848. {
  1849. Warning( "Could not find TitleDataField for %s\n", bindingKeyName );
  1850. continue;
  1851. }
  1852. if ( pField->m_eDataType != TitleDataFieldsDescription_t::DT_uint8 )
  1853. {
  1854. Warning( "%s is expected to be defined as DT_uint8\n", bindingKeyName );
  1855. continue;
  1856. }
  1857. // Finally write the value.
  1858. TitleDataFieldsDescriptionSetValue<uint8>( pField, pPlayerLocal, bindingIndex );
  1859. }
  1860. }
  1861. // Now sync all the device specific convars.
  1862. for (int ii=0; ii<sNumDeviceSpecificSettings; ++ii)
  1863. {
  1864. CFmtStr sFieldLookup( TITLE_DATA_PREFIX "%sCFG.usr.%s", devicePrefix, sDeviceSpecificSettings[ii] );
  1865. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( pFields, sFieldLookup );
  1866. ConVarRef conVarRef( sDeviceSpecificSettings[ii] );
  1867. if ( pField )
  1868. {
  1869. switch( pField->m_eDataType )
  1870. {
  1871. case TitleDataFieldsDescription_t::DT_float:
  1872. if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1873. TitleDataFieldsDescriptionSetValue<float>( pField, pPlayerLocal, conVarRef.GetFloat() );
  1874. else if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1875. conVarRef.SetValue( TitleDataFieldsDescriptionGetValue<float>( pField, pPlayerLocal ) );
  1876. break;
  1877. case TitleDataFieldsDescription_t::DT_uint32:
  1878. if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1879. TitleDataFieldsDescriptionSetValue<int32>( pField, pPlayerLocal, conVarRef.GetInt() );
  1880. else if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1881. conVarRef.SetValue( TitleDataFieldsDescriptionGetValue<int32>( pField, pPlayerLocal ) );
  1882. break;
  1883. case TitleDataFieldsDescription_t::DT_uint16:
  1884. if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1885. TitleDataFieldsDescriptionSetValue<int16>( pField, pPlayerLocal, conVarRef.GetInt() );
  1886. else if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1887. conVarRef.SetValue( TitleDataFieldsDescriptionGetValue<int16>( pField, pPlayerLocal ) );
  1888. break;
  1889. case TitleDataFieldsDescription_t::DT_uint8:
  1890. if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1891. TitleDataFieldsDescriptionSetValue<int8>( pField, pPlayerLocal, conVarRef.GetInt() );
  1892. else if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1893. conVarRef.SetValue( TitleDataFieldsDescriptionGetValue<int8>( pField, pPlayerLocal ) );
  1894. break;
  1895. case TitleDataFieldsDescription_t::DT_BITFIELD:
  1896. if ( eOp == KEYBINDING_WRITE_TO_TITLEDATA )
  1897. TitleDataFieldsDescriptionSetBit( pField, pPlayerLocal, conVarRef.GetBool() );
  1898. else if ( eOp == KEYBINDING_READ_FROM_TITLEDATA )
  1899. conVarRef.SetValue( !!TitleDataFieldsDescriptionGetBit( pField, pPlayerLocal ) );
  1900. break;
  1901. default:
  1902. AssertMsg(false, "Format type not handled in device specific bindings. Have a programmer add the case in." );
  1903. }
  1904. }
  1905. }
  1906. #endif // _GAMECONSOLE
  1907. }
  1908. void ClientModeCSNormal::FireGameEvent( IGameEvent *event )
  1909. {
  1910. if ( GetSplitScreenPlayerSlot() != event->GetInt( "splitscreenplayer" ) )
  1911. return;
  1912. CBaseHudChat *pHudChat = CBaseHudChat::GetHudChat();
  1913. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1914. CLocalPlayerFilter filter;
  1915. // we want to i/o title profile data from menu screens (not just in game) so we bypass checking for C_BasePlayer since we know we have a matchmaking local player
  1916. bool bIgnoreLocalPlayerCheck = false;
  1917. if ( Q_strcmp( "read_game_titledata", event->GetName() ) ==0 || Q_strcmp( "write_game_titledata", event->GetName() ) ==0 )
  1918. bIgnoreLocalPlayerCheck = true;
  1919. if ( !bIgnoreLocalPlayerCheck && ( !pLocalPlayer || !pHudChat ) )
  1920. return;
  1921. const char *eventname = event->GetName();
  1922. if ( !eventname || !eventname[0] )
  1923. return;
  1924. if ( Q_strcmp( "reset_player_controls", eventname ) == 0 )
  1925. {
  1926. if ( this == GetFullscreenClientMode() )
  1927. return;
  1928. engine->ExecuteClientCmd( "exec config" PLATFORM_EXT ".cfg game\n" );
  1929. #if defined( _X360 )
  1930. engine->ExecuteClientCmd( "exec controller" PLATFORM_EXT ".cfg\n" );
  1931. #elif defined( _PS3 )
  1932. engine->ExecuteClientCmd( VarArgs( "cl_reset_ps3_bindings %d %d", GET_ACTIVE_SPLITSCREEN_SLOT(), -1 ) );
  1933. #endif
  1934. }
  1935. if ( Q_strcmp( "round_start", eventname ) == 0 )
  1936. {
  1937. if ( this == GetFullscreenClientMode() )
  1938. return;
  1939. m_iRoundStatus = ROUND_STARTED;
  1940. m_nRoundMVP = 0;
  1941. // recreate all client side physics props
  1942. C_PhysPropClientside::RecreateAll();
  1943. // remove hostage ragdolls
  1944. for ( int i=0; i<g_HostageRagdolls.Count(); ++i )
  1945. {
  1946. // double-check that the EHANDLE is still valid
  1947. if ( g_HostageRagdolls[i] )
  1948. {
  1949. g_HostageRagdolls[i]->Remove();
  1950. }
  1951. }
  1952. g_HostageRagdolls.RemoveAll();
  1953. // Just tell engine to clear decals
  1954. engine->ClientCmd( "r_cleardecals\n" );
  1955. //stop any looping sounds
  1956. // enginesound->StopAllSounds( true );
  1957. CBaseEntity::EmitSound( filter, pLocalPlayer->entindex(), "Music.StopAllExceptMusic" );
  1958. Soundscape_OnStopAllSounds(); // Tell the soundscape system.
  1959. // Remove any left over particle effects from the last round.
  1960. ParticleMgr()->SetRemoveAllParticleEffects();
  1961. GlowObjectManager().UnregisterAllGlowBoxes();
  1962. // remove any stacked up temporary effect events
  1963. engine->ClearEvents();
  1964. #if defined ( _X360 )
  1965. if ( !xboxsystem->IsArcadeTitleUnlocked() )
  1966. {
  1967. int playerInt = event->GetInt( "splitscreenplayer" );
  1968. SplitScreenConVarRef xbox_arcade_remaining_trial_time("xbox_arcade_remaining_trial_time");
  1969. if ( xbox_arcade_remaining_trial_time.GetFloat( playerInt ) < 0.5f )
  1970. {
  1971. // only process this if it is the associated player
  1972. ACTIVE_SPLITSCREEN_PLAYER_GUARD( playerInt );
  1973. if ( this == GetClientModeCSNormal() )
  1974. {
  1975. IGameEvent *event = gameeventmanager->CreateEvent( "trial_time_expired" );
  1976. if ( event )
  1977. {
  1978. event->SetInt( "slot", playerInt );
  1979. gameeventmanager->FireEventClientSide( event );
  1980. }
  1981. engine->ClientCmd_Unrestricted( "disconnect" );
  1982. }
  1983. }
  1984. // verify they have not pulled the MU in an attempt to get past the trial mode time restriction
  1985. CheckTitleDataStorageConnected();
  1986. }
  1987. #endif
  1988. }
  1989. if ( V_strcmp( "round_time_warning", eventname ) == 0 )
  1990. {
  1991. if ( this == GetFullscreenClientMode() )
  1992. return;
  1993. if( !CSGameRules()->m_bBombPlanted )
  1994. {
  1995. PlayMusicSelection( filter, CSMUSIC_ROUNDTEN );
  1996. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  1997. {
  1998. CCSPlayer* pPlayer = ToCSPlayer(UTIL_PlayerByIndex(i));
  1999. if( !pPlayer )
  2000. continue;
  2001. }
  2002. }
  2003. }
  2004. else if ( V_strcmp( "cs_round_start_beep", eventname ) == 0 )
  2005. {
  2006. if ( this == GetFullscreenClientMode() )
  2007. return;
  2008. bool bTeamPanelActive = ( GetViewPortInterface()->GetActivePanel() && ( V_strcmp( GetViewPortInterface()->GetActivePanel()->GetName(), PANEL_TEAM ) == 0 ) );
  2009. if( !bTeamPanelActive )
  2010. {
  2011. CLocalPlayerFilter filter;
  2012. CBaseEntity::EmitSound( filter, 0, "UI.CounterBeep" );
  2013. }
  2014. }
  2015. else if ( V_strcmp( "cs_round_final_beep", eventname ) == 0 )
  2016. {
  2017. if ( this == GetFullscreenClientMode() )
  2018. return;
  2019. bool bTeamPanelActive = ( GetViewPortInterface()->GetActivePanel() && ( V_strcmp( GetViewPortInterface()->GetActivePanel()->GetName(), PANEL_TEAM ) == 0 ) );
  2020. if( !bTeamPanelActive )
  2021. {
  2022. CBaseEntity::EmitSound( filter, 0, "UI.CounterDoneBeep" );
  2023. }
  2024. int nObsMode = pLocalPlayer->GetObserverMode();
  2025. if( nObsMode == OBS_MODE_FIXED || nObsMode == OBS_MODE_ROAMING )
  2026. {
  2027. C_CSPlayer *pCSLocalPlayer = ToCSPlayer(pLocalPlayer);
  2028. if(pCSLocalPlayer->GetCurrentMusic() == CSMUSIC_START )
  2029. {
  2030. CLocalPlayerFilter filter;
  2031. PlayMusicSelection(filter, CSMUSIC_ACTION);
  2032. pCSLocalPlayer->SetCurrentMusic(CSMUSIC_ACTION);
  2033. }
  2034. }
  2035. }
  2036. else if ( V_strcmp( "round_mvp", eventname ) == 0 )
  2037. {
  2038. if ( this == GetFullscreenClientMode() )
  2039. return;
  2040. C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
  2041. if ( pPlayer )
  2042. {
  2043. int nPlayerIndex = pPlayer->entindex();
  2044. if ( C_CS_PlayerResource *cs_PR = dynamic_cast< C_CS_PlayerResource * >( g_PR ) )
  2045. {
  2046. int nMusicID = cs_PR->GetMusicID( nPlayerIndex );
  2047. if ( nMusicID > 1 )
  2048. {
  2049. m_nRoundMVP = nPlayerIndex;
  2050. PlayMusicSelection( filter, CSMUSIC_MVP, nPlayerIndex );
  2051. }
  2052. }
  2053. }
  2054. }
  2055. else if ( Q_strcmp( "round_end", eventname ) == 0 )
  2056. {
  2057. if ( this == GetFullscreenClientMode() )
  2058. return;
  2059. int winningTeam = event->GetInt("winner");
  2060. int reason = event->GetInt("reason");
  2061. if ( Target_Bombed == reason )
  2062. {
  2063. m_iRoundStatus = ROUND_ENDED_VIA_BOMBING;
  2064. }
  2065. else
  2066. {
  2067. m_iRoundStatus = ROUND_ENDED;
  2068. }
  2069. if ( reason != Game_Commencing )
  2070. {
  2071. // if spectating play music for team being spectated at that moment
  2072. C_BasePlayer *pTeamPlayer = pLocalPlayer;
  2073. if( pLocalPlayer->GetTeamNumber() == TEAM_SPECTATOR || pLocalPlayer->IsHLTV() )
  2074. {
  2075. pTeamPlayer = GetHudPlayer();
  2076. }
  2077. if( winningTeam == pTeamPlayer->GetTeamNumber() )
  2078. {
  2079. PlayMusicSelection( filter, CSMUSIC_WONROUND );
  2080. }
  2081. else
  2082. {
  2083. PlayMusicSelection( filter, CSMUSIC_LOSTROUND );
  2084. }
  2085. }
  2086. // play endround announcer sound
  2087. if ( winningTeam == TEAM_CT )
  2088. {
  2089. if ( reason == Bomb_Defused )
  2090. {
  2091. int nAnnouncementLine = 0;
  2092. static char const * const s_arrAnnouncementLines[] = { "Event.BombDefused",
  2093. "Event.BombDefused_Legacy1", "Event.BombDefused_Legacy2", "Event.BombDefused_Legacy3" };
  2094. if ( pLocalPlayer && ( pLocalPlayer->GetTeamNumber() == TEAM_CT ) )
  2095. {
  2096. int nLegacyBragLine = event->GetInt( "legacy" );
  2097. if ( ( nLegacyBragLine >= 1 ) && ( nLegacyBragLine <= 3 ) )
  2098. nAnnouncementLine = nLegacyBragLine;
  2099. }
  2100. // Play "Bomb has been defused" announcement
  2101. C_BaseEntity::EmitSound(filter, SOUND_FROM_LOCAL_PLAYER, s_arrAnnouncementLines[nAnnouncementLine]);
  2102. // Queue up the CT Win audio to play after the bomb defused audio completes
  2103. m_fDelayedCTWinTime = gpGlobals->curtime + C_BaseEntity::GetSoundDuration( s_arrAnnouncementLines[nAnnouncementLine], NULL) + ( nAnnouncementLine ? 0.7 : 0.3 );
  2104. }
  2105. else if ( reason == All_Hostages_Rescued )
  2106. {
  2107. // Queue up the CT Win audio to play after the hostage rescue audio completes
  2108. m_fDelayedCTWinTime = gpGlobals->curtime + C_BaseEntity::GetSoundDuration( "Event.HostageRescued", NULL );
  2109. }
  2110. else
  2111. {
  2112. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.CTWin");
  2113. }
  2114. }
  2115. else if ( winningTeam == TEAM_TERRORIST )
  2116. {
  2117. if ( reason != Terrorists_Planted )
  2118. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.TERWin");
  2119. }
  2120. else
  2121. {
  2122. if ( reason != Game_Commencing )
  2123. {
  2124. // Prevent the round draw sound event from playing when the player spawns into an empty game
  2125. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.RoundDraw");
  2126. }
  2127. }
  2128. // [pfreese] Only show centerprint message for game commencing; the rest of
  2129. // these messages are handled by the end-of-round panel.
  2130. // [Forrest] Show all centerprint messages if the end-of-round panel is disabled.
  2131. static ConVarRef sv_nowinpanel( "sv_nowinpanel" );
  2132. bool isFinishedGunGameRound = CSGameRules()->IsPlayingGunGameProgressive() && (reason == CTs_Win || reason == Terrorists_Win );
  2133. if ( isFinishedGunGameRound || reason == Game_Commencing || sv_nowinpanel.GetBool() )
  2134. {
  2135. // dont show centerprint message anymore
  2136. // we handle this info int he win panel and this info is distracting and redundant
  2137. // GetCenterPrint()->Print( hudtextmessage->LookupString( event->GetString("message") ) );
  2138. // we are starting a new round; store old stats and clear the current match stats
  2139. g_CSClientGameStats.UpdateLastMatchStats();
  2140. g_CSClientGameStats.ResetMatchStats();
  2141. }
  2142. // [jason] Reset the round stats for leaderboards now
  2143. if ( reason == Game_Commencing )
  2144. {
  2145. g_CSClientGameStats.ResetRoundStats();
  2146. }
  2147. }
  2148. else if ( Q_strcmp( "player_team", eventname ) == 0 )
  2149. {
  2150. if ( this == GetFullscreenClientMode() )
  2151. return;
  2152. CBaseHudChat *pHudChat = CBaseHudChat::GetHudChat();
  2153. C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
  2154. if ( !pHudChat )
  2155. return;
  2156. if ( !pPlayer )
  2157. return;
  2158. bool bDisconnected = event->GetBool("disconnect");
  2159. if ( bDisconnected )
  2160. return;
  2161. int iTeam = event->GetInt("team");
  2162. if ( C_BasePlayer::IsLocalPlayer( pPlayer ) )
  2163. {
  2164. ACTIVE_SPLITSCREEN_PLAYER_GUARD( pPlayer );
  2165. // that's me
  2166. pPlayer->TeamChange( iTeam );
  2167. }
  2168. bool bSilent = event->GetBool( "silent" );
  2169. if ( CSGameRules() && CSGameRules()->IsPlayingCoopMission() && pPlayer->IsBot() )
  2170. bSilent = true;
  2171. if ( !bSilent )
  2172. {
  2173. wchar_t wszLocalized[100];
  2174. wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
  2175. char szLocalized[100];
  2176. bool bIsBot = !!event->GetInt("isbot"); // squelch 'bot has joined the game' messages
  2177. if ( iTeam == TEAM_SPECTATOR && !bIsBot )
  2178. {
  2179. g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
  2180. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#Cstrike_game_join_spectators" ), 1, wszPlayerName );
  2181. g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
  2182. pHudChat->Printf( CHAT_FILTER_NONE, "%s", szLocalized );
  2183. }
  2184. else if ( iTeam == TEAM_TERRORIST && !bIsBot )
  2185. {
  2186. g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
  2187. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#Cstrike_game_join_terrorist" ), 1, wszPlayerName );
  2188. g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
  2189. pHudChat->Printf( CHAT_FILTER_NONE, "%s", szLocalized );
  2190. }
  2191. else if ( iTeam == TEAM_CT && !bIsBot )
  2192. {
  2193. g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
  2194. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#Cstrike_game_join_ct" ), 1, wszPlayerName );
  2195. g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) );
  2196. pHudChat->Printf( CHAT_FILTER_NONE, "%s", szLocalized );
  2197. }
  2198. }
  2199. }
  2200. else if ( Q_strcmp( "bomb_planted", eventname ) == 0 )
  2201. {
  2202. // C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
  2203. if ( this == GetFullscreenClientMode() )
  2204. return;
  2205. // show centerprint message when not in training
  2206. if ( !CSGameRules()->IsPlayingTraining() && !CSGameRules()->IsPlayingCooperativeGametype() )
  2207. {
  2208. STEAMWORKS_TESTSECRET_AMORTIZE(5);
  2209. wchar_t wszLocalized[100];
  2210. wchar_t seconds[4];
  2211. V_swprintf_safe( seconds, L"%d", mp_c4timer.GetInt() );
  2212. g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#Cstrike_TitlesTXT_Bomb_Planted" ), 1, seconds );
  2213. GetCenterPrint()->Print( wszLocalized );
  2214. PlayMusicSelection( filter, CSMUSIC_BOMB );
  2215. }
  2216. // play sound
  2217. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.BombPlanted" );
  2218. }
  2219. // else if ( Q_strcmp( "bomb_defused", eventname ) == 0 )
  2220. // {
  2221. // if ( !CSGameRules()->IsPlayingTraining() )
  2222. // {
  2223. // C_CSPlayer *pHudPlayer = GetHudPlayer();
  2224. // C_CSPlayer *pCSLocalPlayer = ToCSPlayer(pLocalPlayer);
  2225. //
  2226. // // music logic says: if mvp has music pack, play that. else, if spectating play win/lose and pack of hudplayer.. else play local win/lose and pack.
  2227. // C_CSPlayer *pMusicPlayer = pCSLocalPlayer ? pCSLocalPlayer : pHudPlayer;
  2228. // if( pCSLocalPlayer->GetTeamNumber() == TEAM_SPECTATOR || pCSLocalPlayer->IsHLTV() )
  2229. // {
  2230. // pMusicPlayer = pHudPlayer;
  2231. // }
  2232. //
  2233. // if ( pMusicPlayer->GetTeamNumber() == TEAM_CT)
  2234. // {
  2235. // PlayMusicSelection( filter, CSMUSIC_WONROUND );
  2236. // }
  2237. // else
  2238. // {
  2239. // PlayMusicSelection( filter, CSMUSIC_LOSTROUND );
  2240. // }
  2241. // }
  2242. // }
  2243. // [menglish] Tell the client side bomb that the bomb has exploding here creating the explosion particle effect
  2244. else if ( Q_strcmp( "bomb_exploded", eventname ) == 0 )
  2245. {
  2246. if ( this == GetFullscreenClientMode() )
  2247. return;
  2248. if ( g_PlantedC4s.Count() > 0 )
  2249. {
  2250. // bomb is planted
  2251. C_PlantedC4 *pC4 = g_PlantedC4s[0];
  2252. pC4->Explode();
  2253. }
  2254. //pLocalPlayer->EmitSound( "Music.StopAllMusic" );
  2255. }
  2256. else if ( Q_strcmp( "hostage_follows", eventname ) == 0 )
  2257. {
  2258. if ( this == GetFullscreenClientMode() )
  2259. return;
  2260. // show centerprint message when not in training
  2261. if ( !CSGameRules()->IsPlayingTraining() )
  2262. {
  2263. GetCenterPrint()->Print( "#Cstrike_TitlesTXT_Hostage_Being_Taken" );
  2264. bool roundWasAlreadyWon = ( CSGameRules()->m_iRoundWinStatus != WINNER_NONE );
  2265. if ( !roundWasAlreadyWon )
  2266. {
  2267. PlayMusicSelection( filter, CSMUSIC_HOSTAGE );
  2268. }
  2269. }
  2270. }
  2271. else if ( Q_strcmp( "hostage_killed", eventname ) == 0 )
  2272. {
  2273. if ( this == GetFullscreenClientMode() )
  2274. return;
  2275. // play sound for spectators and CTs
  2276. if ( pLocalPlayer->IsObserver() || (pLocalPlayer->GetTeamNumber() == TEAM_CT) )
  2277. {
  2278. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.HostageKilled") ;
  2279. }
  2280. // Show warning to killer
  2281. if ( pLocalPlayer->GetUserID() == event->GetInt("userid") )
  2282. {
  2283. GetCenterPrint()->Print( "#Cstrike_TitlesTXT_Killed_Hostage" );
  2284. }
  2285. }
  2286. else if ( Q_strcmp( "hostage_hurt", eventname ) == 0 )
  2287. {
  2288. if ( this == GetFullscreenClientMode() )
  2289. return;
  2290. // Let the loacl player know he harmed a hostage
  2291. if ( pLocalPlayer->GetUserID() == event->GetInt("userid") )
  2292. {
  2293. GetCenterPrint()->Print( "#Cstrike_TitlesTXT_Injured_Hostage" );
  2294. }
  2295. }
  2296. else if ( Q_strcmp( "player_death", eventname ) == 0 )
  2297. {
  2298. if ( this == GetFullscreenClientMode() )
  2299. return;
  2300. C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
  2301. C_CSPlayer* csPlayer = ToCSPlayer(pPlayer);
  2302. if (csPlayer)
  2303. {
  2304. csPlayer->ClearSoundEvents();
  2305. }
  2306. if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
  2307. {
  2308. // we just died, hide any buy panels
  2309. CSGameRules()->CloseBuyMenu( pLocalPlayer->GetUserID() );
  2310. }
  2311. }
  2312. else if ( Q_strcmp( "player_changename", eventname ) == 0 )
  2313. {
  2314. return; // server sends a colorized text string for this
  2315. }
  2316. else if ( Q_strcmp( "seasoncoin_levelup", eventname ) == 0 )
  2317. {
  2318. if ( this == GetFullscreenClientMode() )
  2319. {
  2320. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  2321. int iPlayerIndex = event->GetInt( "player" );
  2322. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2323. //int iCategory = event->GetInt( "category" );
  2324. int iRank = event->GetInt( "rank" );
  2325. if ( !hudChat || !pPlayer )
  2326. return;
  2327. if ( C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR ) )
  2328. {
  2329. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH];
  2330. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2331. wchar_t wszLocalizedString[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2332. if ( iRank == MEDAL_RANK_SILVER )
  2333. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#SEASONX_Coin_LevelUp_Silver" ), 1, wszPlayerName );
  2334. else if ( iRank == MEDAL_RANK_GOLD )
  2335. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#SEASONX_Coin_LevelUp_Gold" ), 1, wszPlayerName );
  2336. if ( wszLocalizedString[0] )
  2337. {
  2338. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2339. }
  2340. }
  2341. }
  2342. }
  2343. // [tj] We handle this here instead of in the base class
  2344. // The reason is that we don't use string tables to localize.
  2345. // Instead, we use the steam localization mechanism.
  2346. else if ( Q_strcmp( "achievement_earned", eventname ) == 0 )
  2347. {
  2348. if ( this == GetFullscreenClientMode() )
  2349. {
  2350. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  2351. int iPlayerIndex = event->GetInt( "player" );
  2352. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2353. int iAchievement = event->GetInt( "achievement" );
  2354. if ( !hudChat || !pPlayer )
  2355. return;
  2356. if ( !g_AchievementMgrCS.CheckAchievementsEnabled() )
  2357. return;
  2358. IAchievement *pAchievement = g_AchievementMgrCS.GetAchievementByID( iAchievement, GetSplitScreenPlayerSlot() );
  2359. if ( pAchievement )
  2360. {
  2361. if ( pPlayer->ShouldAnnounceAchievement() || C_BasePlayer::IsLocalPlayer( pPlayer ) )
  2362. {
  2363. pPlayer->SetNextAchievementAnnounceTime( gpGlobals->curtime + ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME );
  2364. //Do something for the player - Actually we should probably do this client-side when the achievement is first earned.
  2365. if (pPlayer->IsLocalPlayer())
  2366. {
  2367. }
  2368. pPlayer->OnAchievementAchieved( iAchievement );
  2369. if ( C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR ) )
  2370. {
  2371. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH];
  2372. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), (EDecoratedPlayerNameFlag_t)( k_EDecoratedPlayerNameFlag_DontMakeStringSafe | k_EDecoratedPlayerNameFlag_DontUseAssassinationTargetName ) );
  2373. wchar_t achievementName[1024];
  2374. const wchar_t* constAchievementName = &achievementName[0];
  2375. constAchievementName = ACHIEVEMENT_LOCALIZED_NAME( pAchievement );
  2376. if (constAchievementName)
  2377. {
  2378. wchar_t wszLocalizedString[2 * MAX_DECORATED_PLAYER_NAME_LENGTH];
  2379. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#Achievement_Earned" ), 2, wszPlayerName, constAchievementName/*wszAchievementString*/ );
  2380. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2381. }
  2382. }
  2383. }
  2384. }
  2385. }
  2386. }
  2387. else if ( Q_strcmp( "item_found", eventname ) == 0 )
  2388. {
  2389. if ( this == GetFullscreenClientMode() )
  2390. {
  2391. //
  2392. // LEGACY game event handler to correctly print items uncased in demos before May 2014
  2393. //
  2394. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  2395. int iPlayerIndex = event->GetInt( "player" );
  2396. // int iItemRarity = event->GetInt( "quality" );
  2397. int iMethod = event->GetInt( "method" );
  2398. int iItemDef = event->GetInt( "itemdef" );
  2399. uint64 itemID = event->GetInt( "itemid", -1 );
  2400. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2401. const GameItemDefinition_t *pItemDefinition = dynamic_cast<const GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( iItemDef ) );
  2402. // White list of item acquisitions to print in chat.
  2403. if ( ( iMethod != ( UNACK_ITEM_FOUND_IN_CRATE - 1 ) ) &&
  2404. ( iMethod != ( UNACK_ITEM_PURCHASED - 1 ) ) &&
  2405. ( iMethod != ( UNACK_ITEM_TRADED - 1 ) ) &&
  2406. ( iMethod != ( UNACK_ITEM_CRAFTED - 1 ) ) &&
  2407. ( iMethod != ( UNACK_ITEM_GIFTED - 1 ) ) )
  2408. return;
  2409. if ( !pPlayer || !pItemDefinition )
  2410. return;
  2411. if ( C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR ) )
  2412. {
  2413. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH];
  2414. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2415. if ( iMethod < 0 || iMethod >= ARRAYSIZE( g_pszItemFoundMethodStrings ) )
  2416. {
  2417. iMethod = 0;
  2418. }
  2419. const char *pszLocString = g_pszItemFoundMethodStrings[iMethod];
  2420. wchar_t const *wszItemFound = pszLocString ? g_pVGuiLocalize->Find( pszLocString ) : NULL;
  2421. if ( wszItemFound )
  2422. {
  2423. // TODO: Update the localization strings to only have two format parameters since that's all we need.
  2424. CSteamID steamID;
  2425. wchar_t wszLocalizedString[2 * MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2426. bool bUsingFullName = false;
  2427. if ( itemID != -1 && pPlayer->GetSteamID( &steamID ) )
  2428. {
  2429. CCSPlayerInventory* pPlayerInv = CSInventoryManager()->GetInventoryForPlayer( steamID );
  2430. if ( pPlayerInv )
  2431. {
  2432. CEconItemView* pEconItem = pPlayerInv->GetInventoryItemByItemID( itemID );
  2433. if ( pEconItem )
  2434. {
  2435. int nRarity = pEconItem->GetRarity() - 1;
  2436. wchar_t wszItemName[256];
  2437. _snwprintf( wszItemName, ARRAYSIZE( wszItemName ), L"%c" PRI_WS_FOR_WS L"\01", nRarity + COLOR_RARITY_FIRST, pEconItem->GetItemName() );
  2438. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, wszItemName, L"" );
  2439. bUsingFullName = true;
  2440. }
  2441. }
  2442. }
  2443. if ( !bUsingFullName )
  2444. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, g_pVGuiLocalize->Find( pItemDefinition->GetItemBaseName() ), L"" );
  2445. if ( wszLocalizedString[0] )
  2446. {
  2447. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2448. }
  2449. }
  2450. }
  2451. }
  2452. }
  2453. else if ( Q_strcmp( "items_gifted", eventname ) == 0 )
  2454. {
  2455. if ( ( this == GetFullscreenClientMode() ) && ( event->GetInt( "giftidx" ) == 0 ) )
  2456. { // PUBLIC GIFT ANNOUNCEMENT -- print info when event comes about the first gift in the batch
  2457. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  2458. int iPlayerIndex = event->GetInt( "player" );
  2459. int iItemDef = event->GetInt( "itemdef" );
  2460. int numGifts = event->GetInt( "numgifts" );
  2461. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2462. const GameItemDefinition_t *pItemDefinition = dynamic_cast< const GameItemDefinition_t* >( GetItemSchema()->GetItemDefinition( iItemDef ) );
  2463. if ( !pPlayer || !pItemDefinition )
  2464. return;
  2465. if ( C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR ) )
  2466. { // [VITALIY] has given out a gift! ///OR/// [VITALIY] has given out 25 gifts!
  2467. char const *fmtMessageLoc = ( numGifts > 1 ) ? "#Item_GiftsSentMany" : "#Item_GiftsSent1Anon";
  2468. wchar_t wszArg2[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2469. V_snwprintf( wszArg2, Q_ARRAYSIZE( wszArg2 ), L"%d", numGifts );
  2470. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2471. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2472. if ( wchar_t const *wszLocToken = g_pVGuiLocalize->Find( fmtMessageLoc ) )
  2473. {
  2474. wchar_t wszLocalizedString[2 * MAX_DECORATED_PLAYER_NAME_LENGTH];
  2475. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszLocToken, 2, wszPlayerName, wszArg2 );
  2476. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2477. }
  2478. }
  2479. }
  2480. if ( this == GetFullscreenClientMode() )
  2481. { // print gift details if a local player is one of the players involved in the gift exchange
  2482. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  2483. int iPlayerIndex = event->GetInt( "player" );
  2484. int iItemDef = event->GetInt( "itemdef" );
  2485. uint32 unAccountID = event->GetInt( "accountid" );
  2486. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  2487. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2488. const GameItemDefinition_t *pItemDefinition = dynamic_cast< const GameItemDefinition_t* >( GetItemSchema()->GetItemDefinition( iItemDef ) );
  2489. C_CS_PlayerResource *cs_PR = dynamic_cast<C_CS_PlayerResource *>( g_PR );
  2490. if ( !pPlayer || !pItemDefinition || !pLocalPlayer || !cs_PR )
  2491. return;
  2492. if ( pLocalPlayer == pPlayer )
  2493. {
  2494. // Local player is the gifter!
  2495. CSteamID steamID;
  2496. CBasePlayer *pFoundRecipient = NULL;
  2497. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  2498. {
  2499. C_BasePlayer *pPlayer = ToBasePlayer( UTIL_PlayerByIndex( i ) );
  2500. if ( pPlayer == NULL )
  2501. continue;
  2502. if ( pPlayer->GetSteamID( &steamID ) == false )
  2503. continue;
  2504. if ( steamID.GetAccountID() == unAccountID )
  2505. {
  2506. pFoundRecipient = pPlayer;
  2507. break;
  2508. }
  2509. }
  2510. // Print who got my gift? (if the person is in my game server, as opposed to spectating via twitch.tv/GOTV)
  2511. if ( pFoundRecipient )
  2512. {
  2513. wchar_t wszArg2[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2514. cs_PR->GetDecoratedPlayerName( pFoundRecipient->entindex(), wszArg2, sizeof( wszArg2 ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2515. char const *fmtMessageLoc = "#Item_GiftsYouSentGift";
  2516. if ( wchar_t const *wszLocToken = g_pVGuiLocalize->Find( fmtMessageLoc ) )
  2517. {
  2518. wchar_t wszLocalizedString[2 * MAX_DECORATED_PLAYER_NAME_LENGTH];
  2519. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszLocToken, 1, wszArg2 );
  2520. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2521. }
  2522. }
  2523. }
  2524. else if ( unAccountID == steamapicontext->SteamUser()->GetSteamID().GetAccountID() )
  2525. {
  2526. // Local player got a gift!
  2527. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  2528. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2529. char const *fmtMessageLoc = "#Item_GiftsYouGotGift";
  2530. if ( wchar_t const *wszLocToken = g_pVGuiLocalize->Find( fmtMessageLoc ) )
  2531. {
  2532. wchar_t wszLocalizedString[2 * MAX_DECORATED_PLAYER_NAME_LENGTH];
  2533. g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszLocToken, 1, wszPlayerName );
  2534. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2535. // Play a sound for the local player
  2536. // CLocalPlayerFilter filter;
  2537. // C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "UI.ContractSeal" );
  2538. }
  2539. }
  2540. }
  2541. }
  2542. else if ( Q_strcmp( "write_game_titledata", eventname ) == 0 )
  2543. {
  2544. #if !defined( _PS3 )
  2545. SyncCurrentKeyBindingsToDeviceTitleData( event->GetInt( "controllerId" ), INPUT_DEVICE_NONE, KEYBINDING_WRITE_TO_TITLEDATA );
  2546. #endif
  2547. }
  2548. else if ( Q_strcmp( "read_game_titledata", eventname ) == 0 )
  2549. {
  2550. #if !defined( _PS3 )
  2551. SyncCurrentKeyBindingsToDeviceTitleData( event->GetInt( "controllerId" ), INPUT_DEVICE_NONE, KEYBINDING_READ_FROM_TITLEDATA );
  2552. #endif
  2553. }
  2554. else if ( V_strcmp( "switch_team", eventname ) == 0 )
  2555. {
  2556. if ( this == GetFullscreenClientMode() )
  2557. return;
  2558. // Someone in the game joined or changed teams. Notify matchmaking that it needs to update any
  2559. // properties based on team distribution.
  2560. if ( g_pMatchFramework && g_PR )
  2561. {
  2562. int numPlayers = event->GetInt( "numPlayers" );
  2563. int numSpectators = event->GetInt( "numSpectators" );
  2564. int avgRank = event->GetInt( "timeout" );
  2565. int numTSlotsFree = event->GetInt( "numTSlotsFree" );
  2566. int numCTSlotsFree = event->GetInt( "numCTSlotsFree" );
  2567. KeyValues *pTeamProperties = new KeyValues( "switch_team" );
  2568. KeyValues::AutoDelete autoDeleteEvent( pTeamProperties );
  2569. pTeamProperties->SetInt( "members/numPlayers", numPlayers );
  2570. pTeamProperties->SetInt( "members/numSpectators", numSpectators );
  2571. pTeamProperties->SetInt( "members/timeout", avgRank );
  2572. pTeamProperties->SetInt( "members/numTSlotsFree", numTSlotsFree );
  2573. pTeamProperties->SetInt( "members/numCTSlotsFree", numCTSlotsFree );
  2574. g_pMatchFramework->UpdateTeamProperties( pTeamProperties );
  2575. }
  2576. }
  2577. else
  2578. {
  2579. BaseClass::FireGameEvent( event );
  2580. }
  2581. }
  2582. bool __MsgFunc_SendPlayerItemFound( const CCSUsrMsg_SendPlayerItemFound &msg )
  2583. {
  2584. CBaseHudChat *hudChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat );
  2585. int iPlayerIndex = msg.entindex();
  2586. int iMethod = GetUnacknowledgedReason( msg.iteminfo().inventory() ) - 1;
  2587. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  2588. // White list of item acquisitions to print in chat.
  2589. if ( ( iMethod != ( UNACK_ITEM_FOUND_IN_CRATE - 1 ) ) &&
  2590. ( iMethod != ( UNACK_ITEM_PURCHASED - 1 ) ) &&
  2591. ( iMethod != ( UNACK_ITEM_TRADED - 1 ) ) &&
  2592. ( iMethod != ( UNACK_ITEM_CRAFTED - 1 ) ) &&
  2593. ( iMethod != ( UNACK_ITEM_GIFTED - 1 ) ) )
  2594. return true;
  2595. if ( !pPlayer )
  2596. return true;
  2597. if ( C_CS_PlayerResource *cs_PR = dynamic_cast< C_CS_PlayerResource * >( g_PR ) )
  2598. {
  2599. wchar_t wszPlayerName[ MAX_DECORATED_PLAYER_NAME_LENGTH ];
  2600. cs_PR->GetDecoratedPlayerName( iPlayerIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_DontMakeStringSafe );
  2601. if ( iMethod < 0 || iMethod >= ARRAYSIZE( g_pszItemFoundMethodStrings ) )
  2602. {
  2603. iMethod = 0;
  2604. }
  2605. const char *pszLocString = g_pszItemFoundMethodStrings[ iMethod ];
  2606. wchar_t *wszItemFound = pszLocString ? g_pVGuiLocalize->Find( pszLocString ) : NULL;
  2607. if ( wszItemFound )
  2608. {
  2609. wchar_t wszLocalizedString[ 2 * MAX_DECORATED_PLAYER_NAME_LENGTH ] = {};
  2610. if ( wszLocalizedString[0] )
  2611. {
  2612. hudChat->ChatPrintfW( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, wszLocalizedString );
  2613. }
  2614. }
  2615. }
  2616. return true;
  2617. }
  2618. void ClientModeCSNormal::OnEvent( KeyValues *pEvent )
  2619. {
  2620. const char *pEventName = pEvent->GetName();
  2621. if ( 0 == Q_strcmp( pEventName, "OnSysStorageDevicesChanged" ) )
  2622. {
  2623. CheckTitleDataStorageConnected();
  2624. }
  2625. }
  2626. #if defined ( _X360 )
  2627. CON_COMMAND_F( boot_to_start_and_reset_config, "Reset the profile for the indexed player and then go to the start screen", FCVAR_DEVELOPMENTONLY )
  2628. {
  2629. if ( args.ArgC() <= 1 || args.ArgC() > 2)
  2630. {
  2631. ConMsg( "Usage: boot_to_start_and_reset_config: <playerIndex>\n" );
  2632. return;
  2633. }
  2634. if ( args.ArgC() == 2 )
  2635. {
  2636. int slot = atoi( args[1] );
  2637. engine->ClientCmd_Unrestricted( VarArgs( "host_reset_config %d", slot ) );
  2638. engine->ClientCmd_Unrestricted( VarArgs( "host_writeconfig_ss %d", slot ) );
  2639. engine->ClientCmd_Unrestricted( "disconnect" );
  2640. BasePanel()->SetForceStartScreen();
  2641. BasePanel()->HandleOpenCreateStartScreen();
  2642. }
  2643. }
  2644. CON_COMMAND_F( boot_to_start, "Go to the start screen", FCVAR_DEVELOPMENTONLY )
  2645. {
  2646. engine->ClientCmd_Unrestricted( "disconnect" );
  2647. BasePanel()->SetForceStartScreen();
  2648. BasePanel()->HandleOpenCreateStartScreen();
  2649. }
  2650. #endif
  2651. void ClientModeCSNormal::CheckTitleDataStorageConnected( void )
  2652. {
  2653. #if defined ( _X360 )
  2654. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  2655. if ( this != GetClientModeCSNormal() )
  2656. return;
  2657. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( XBX_GetActiveUserId() );
  2658. if ( pPlayer )
  2659. {
  2660. if ( !pPlayer->IsTitleDataStorageConnected() )
  2661. {
  2662. if ( !xboxsystem->IsArcadeTitleUnlocked() )
  2663. {
  2664. // Here we know that you have pulled the storage unit that we need to save your progress; since you are in trial mode, we boot you back to the start screen
  2665. // Need to inform player that they must have a storage device connected to their profile in order to play in trial mode and hence they got kicked
  2666. int iSlot = XBX_GetSlotByUserId( XBX_GetActiveUserId() );
  2667. ECommandMsgBoxSlot slot = CMB_SLOT_FULL_SCREEN;
  2668. if ( GameUI().IsInLevel() )
  2669. {
  2670. if ( iSlot == 0 )
  2671. {
  2672. slot = CMB_SLOT_PLAYER_0;
  2673. }
  2674. else
  2675. {
  2676. slot = CMB_SLOT_PLAYER_1;
  2677. }
  2678. }
  2679. GameUI().CreateCommandMsgBoxInSlot(
  2680. slot,
  2681. "#SFUI_TrialMUPullTitle",
  2682. "#SFUI_TrialMUPullMsg",
  2683. true,
  2684. false,
  2685. "boot_to_start",
  2686. NULL,
  2687. NULL,
  2688. NULL );
  2689. }
  2690. else
  2691. {
  2692. // Here we know that you have pulled the storage unit that we need to save your progress; we need to inform user they wont be able to save stats/etc
  2693. // until they reattach the storage unit
  2694. }
  2695. }
  2696. }
  2697. #endif
  2698. }
  2699. void RemoveClassImageEntity()
  2700. {
  2701. C_BaseAnimating *pEnt = g_ClassImagePlayer.Get();
  2702. if ( pEnt )
  2703. {
  2704. pEnt->Remove();
  2705. g_ClassImagePlayer = NULL;
  2706. }
  2707. pEnt = g_ClassImageWeapon.Get();
  2708. if ( pEnt )
  2709. {
  2710. pEnt->Remove();
  2711. g_ClassImagePlayer = NULL;
  2712. }
  2713. }
  2714. bool ShouldRecreateClassImageEntity( C_BaseAnimating *pEnt, const char *pNewModelName )
  2715. {
  2716. if ( !pNewModelName || !pNewModelName[0] )
  2717. return false;
  2718. if ( !pEnt )
  2719. return true;
  2720. const model_t *pModel = pEnt->GetModel();
  2721. if ( !pModel )
  2722. return true;
  2723. const char *pName = modelinfo->GetModelName( pModel );
  2724. if ( !pName )
  2725. return true;
  2726. // reload only if names are different
  2727. const char *pNameNoPath = V_UnqualifiedFileName( pName );
  2728. const char *pNewModelNameNoPath = V_UnqualifiedFileName( pNewModelName );
  2729. return( Q_stricmp( pNameNoPath, pNewModelNameNoPath ) != 0 );
  2730. }
  2731. #if !defined( CSTRIKE15 )
  2732. // Draw a doll of a player character for the team selection VGUI screen.
  2733. static void UpdateClassImageEntity(
  2734. const char *pModelName,
  2735. int x, int y, int width, int height )
  2736. {
  2737. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  2738. if ( !pLocalPlayer )
  2739. return;
  2740. MDLCACHE_CRITICAL_SECTION();
  2741. const char *pWeaponName = "models/weapons/w_rif_ak47.mdl";
  2742. const char *pWeaponSequence = "Walk_Upper_AK";
  2743. int i;
  2744. for ( i=0; i<CTPlayerModels.Count(); ++i )
  2745. {
  2746. if ( Q_strcasecmp( pModelName, CTPlayerModels[i] ) == 0 )
  2747. {
  2748. // give CTs a M4
  2749. pWeaponName = "models/weapons/w_rif_m4a1.mdl";
  2750. pWeaponSequence = "Walk_Upper_M4";
  2751. break;
  2752. }
  2753. }
  2754. if ( pLocalPlayer->IsAlive() && pLocalPlayer->GetActiveWeapon() )
  2755. {
  2756. C_WeaponCSBase *weapon = dynamic_cast< C_WeaponCSBase * >(pLocalPlayer->GetActiveWeapon());
  2757. if ( weapon )
  2758. {
  2759. pWeaponName = weapon->GetWorldModel();
  2760. pWeaponSequence = VarArgs("Walk_Upper_%s", weapon->GetPlayerAnimationExtension());
  2761. }
  2762. }
  2763. C_BaseAnimatingOverlay *pPlayerModel = g_ClassImagePlayer.Get();
  2764. // Does the entity even exist yet?
  2765. bool recreatePlayer = ShouldRecreateClassImageEntity( pPlayerModel, pModelName );
  2766. if ( recreatePlayer )
  2767. {
  2768. if ( pPlayerModel )
  2769. pPlayerModel->Remove();
  2770. pPlayerModel = new C_BaseAnimatingOverlay;
  2771. pPlayerModel->InitializeAsClientEntity( pModelName, false );
  2772. pPlayerModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
  2773. // let player walk ahead
  2774. pPlayerModel->SetSequence( pPlayerModel->LookupSequence( "walk_lower" ) );
  2775. pPlayerModel->SetPoseParameter( "move_yaw", 0.0f ); // move_yaw
  2776. pPlayerModel->SetPoseParameter( "body_pitch", 10.0f ); // body_pitch, look down a bit
  2777. pPlayerModel->SetPoseParameter( "body_yaw", 0.0f ); // body_yaw
  2778. pPlayerModel->SetPoseParameter( "move_y", 0.0f ); // move_y
  2779. pPlayerModel->SetPoseParameter( "move_x", 1.0f ); // move_x, walk forward
  2780. pPlayerModel->m_flAnimTime = gpGlobals->curtime;
  2781. g_ClassImagePlayer = pPlayerModel;
  2782. }
  2783. C_BaseAnimating *pWeaponModel = g_ClassImageWeapon.Get();
  2784. // Does the entity even exist yet?
  2785. if ( recreatePlayer || ShouldRecreateClassImageEntity( pWeaponModel, pWeaponName ) )
  2786. {
  2787. if ( pWeaponModel )
  2788. pWeaponModel->Remove();
  2789. pWeaponModel = new C_BaseAnimating;
  2790. pWeaponModel->InitializeAsClientEntity( pWeaponName, false );
  2791. pWeaponModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
  2792. pWeaponModel->FollowEntity( pPlayerModel ); // attach to player model
  2793. pWeaponModel->m_flAnimTime = gpGlobals->curtime;
  2794. g_ClassImageWeapon = pWeaponModel;
  2795. }
  2796. Vector origin = pLocalPlayer->EyePosition();
  2797. Vector lightOrigin = origin;
  2798. // find a spot inside the world for the dlight's origin, or it won't illuminate the model
  2799. Vector testPos( origin.x - 100, origin.y, origin.z + 100 );
  2800. trace_t tr;
  2801. UTIL_TraceLine( origin, testPos, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
  2802. if ( tr.fraction == 1.0f )
  2803. {
  2804. lightOrigin = tr.endpos;
  2805. }
  2806. else
  2807. {
  2808. // Now move the model away so we get the correct illumination
  2809. lightOrigin = tr.endpos + Vector( 1, 0, -1 ); // pull out from the solid
  2810. Vector start = lightOrigin;
  2811. Vector end = lightOrigin + Vector( 100, 0, -100 );
  2812. UTIL_TraceLine( start, end, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
  2813. origin = tr.endpos;
  2814. }
  2815. // move player model in front of our view
  2816. pPlayerModel->SetAbsOrigin( origin );
  2817. pPlayerModel->SetAbsAngles( QAngle( 0, 210, 0 ) );
  2818. // wacky hacky, set upper body animation
  2819. pPlayerModel->m_SequenceTransitioner.CheckForSequenceChange(
  2820. pPlayerModel->GetModelPtr(),
  2821. pPlayerModel->LookupSequence( "walk_lower" ),
  2822. false,
  2823. true
  2824. );
  2825. pPlayerModel->m_SequenceTransitioner.UpdateCurrent(
  2826. pPlayerModel->GetModelPtr(),
  2827. pPlayerModel->LookupSequence( "walk_lower" ),
  2828. pPlayerModel->GetCycle(),
  2829. pPlayerModel->GetPlaybackRate(),
  2830. gpGlobals->realtime
  2831. );
  2832. // Now, blend the lower and upper (aim) anims together
  2833. pPlayerModel->SetNumAnimOverlays( 2 );
  2834. int numOverlays = pPlayerModel->GetNumAnimOverlays();
  2835. for ( i=0; i < numOverlays; ++i )
  2836. {
  2837. C_AnimationLayer *layer = pPlayerModel->GetAnimOverlay( i );
  2838. layer->SetCycle( pPlayerModel->GetCycle() );
  2839. if ( i )
  2840. layer->SetSequence( pPlayerModel->LookupSequence( pWeaponSequence ) );
  2841. else
  2842. layer->SetSequence( pPlayerModel->LookupSequence( "walk_lower" ) );
  2843. layer->SetPlaybackRate( 1.0 );
  2844. layer->SetWeight( 1.0f );
  2845. layer->SetOrder( i );
  2846. }
  2847. pPlayerModel->FrameAdvance( gpGlobals->frametime );
  2848. // Now draw it.
  2849. CViewSetup view;
  2850. view.x = x;
  2851. view.y = y;
  2852. view.width = width;
  2853. view.height = height;
  2854. view.m_bOrtho = false;
  2855. view.fov = 54;
  2856. view.origin = origin + Vector( -110, -5, -5 );
  2857. Vector vMins, vMaxs;
  2858. pPlayerModel->C_BaseAnimating::GetRenderBounds( vMins, vMaxs );
  2859. view.origin.z += ( vMins.z + vMaxs.z ) * 0.55f;
  2860. view.angles.Init();
  2861. view.zNear = VIEW_NEARZ;
  2862. view.zFar = 1000;
  2863. Frustum dummyFrustum;
  2864. CMatRenderContextPtr pRenderContext( materials );
  2865. render->Push3DView( pRenderContext, view, 0, NULL, dummyFrustum );
  2866. // [mhansen] We don't want to light the model in the world. We want it to
  2867. // always be lit normal like even if you are standing in a dark (or green) area
  2868. // in the world.
  2869. pRenderContext->SetLightingOrigin( vec3_origin );
  2870. LightDesc_t ld;
  2871. ld.InitDirectional( Vector( 0.0f, 0.0f, -1.0f ), Vector( 1.0f, 1.0f, 0.8f ) );
  2872. pRenderContext->SetLights( 1, &ld );
  2873. static Vector white[6] =
  2874. {
  2875. Vector( 0.4, 0.4, 0.4 ),
  2876. Vector( 0.4, 0.4, 0.4 ),
  2877. Vector( 0.4, 0.4, 0.4 ),
  2878. Vector( 0.4, 0.4, 0.4 ),
  2879. Vector( 0.4, 0.4, 0.4 ),
  2880. Vector( 0.4, 0.4, 0.4 ),
  2881. };
  2882. g_pStudioRender->SetAmbientLightColors( white );
  2883. g_pStudioRender->SetLocalLights( 0, NULL );
  2884. modelrender->SuppressEngineLighting( true );
  2885. float color[3] = { 1.0f, 1.0f, 1.0f };
  2886. render->SetColorModulation( color );
  2887. render->SetBlend( 1.0f );
  2888. RenderableInstance_t instance;
  2889. instance.m_nAlpha = 255;
  2890. pPlayerModel->DrawModel( STUDIO_RENDER, instance );
  2891. if ( pWeaponModel )
  2892. {
  2893. pWeaponModel->DrawModel( STUDIO_RENDER, instance );
  2894. }
  2895. modelrender->SuppressEngineLighting( false );
  2896. render->PopView( pRenderContext, dummyFrustum );
  2897. }
  2898. #endif // CSTRIKE15
  2899. bool WillPanelBeVisible( vgui::VPANEL hPanel )
  2900. {
  2901. while ( hPanel )
  2902. {
  2903. if ( !vgui::ipanel()->IsVisible( hPanel ) )
  2904. return false;
  2905. hPanel = vgui::ipanel()->GetParent( hPanel );
  2906. }
  2907. return true;
  2908. }
  2909. void ClientModeCSNormal::PreRender(CViewSetup *pSetup)
  2910. {
  2911. ClientModeShared::PreRender( pSetup );
  2912. // Make sure preview decals update before the current render pass every frame (if needed of course)
  2913. extern void UpdatePreviewDecal();
  2914. UpdatePreviewDecal();
  2915. }
  2916. void ClientModeCSNormal::PostRenderVGui()
  2917. {
  2918. #if !defined( CSTRIKE15 )
  2919. // If the team menu is up, then we will render the model of the character that is currently selected.
  2920. for ( int i=0; i < g_ClassImagePanels.Count(); i++ )
  2921. {
  2922. CCSClassImagePanel *pPanel = g_ClassImagePanels[i];
  2923. if ( WillPanelBeVisible( pPanel->GetVPanel() ) )
  2924. {
  2925. // Ok, we have a visible class image panel.
  2926. int x, y, w, h;
  2927. pPanel->GetBounds( x, y, w, h );
  2928. pPanel->LocalToScreen( x, y );
  2929. // Allow for the border.
  2930. x += 3;
  2931. y += 5;
  2932. w -= 2;
  2933. h -= 10;
  2934. UpdateClassImageEntity( g_ClassImagePanels[i]->m_ModelName, x, y, w, h );
  2935. return;
  2936. }
  2937. }
  2938. #endif // !CSTRIKE15
  2939. }
  2940. bool ClientModeCSNormal::ShouldDrawViewModel( void )
  2941. {
  2942. C_CSPlayer *pPlayer = GetHudPlayer();
  2943. if( pPlayer && pPlayer->GetFOV() != CSGameRules()->DefaultFOV() && pPlayer->m_bIsScoped )
  2944. {
  2945. CWeaponCSBase *pWpn = pPlayer->GetActiveCSWeapon();
  2946. if( pWpn && pWpn->DoesHideViewModelWhenZoomed() )
  2947. {
  2948. return false;
  2949. }
  2950. }
  2951. return BaseClass::ShouldDrawViewModel();
  2952. }
  2953. bool ClientModeCSNormal::CanRecordDemo( char *errorMsg, int length ) const
  2954. {
  2955. C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
  2956. if ( !player )
  2957. {
  2958. return true;
  2959. }
  2960. if ( !player->IsAlive() )
  2961. {
  2962. return true;
  2963. }
  2964. // don't start recording while flashed, as it would remove the flash
  2965. if ( player->m_flFlashBangTime > gpGlobals->curtime )
  2966. {
  2967. Q_strncpy( errorMsg, "Cannot record demos while blind.", length );
  2968. return false;
  2969. }
  2970. // don't start recording while smoke grenades are spewing smoke, as the existing smoke would be destroyed
  2971. C_BaseEntityIterator it;
  2972. C_BaseEntity *ent;
  2973. while ( (ent = it.Next()) != NULL )
  2974. {
  2975. if ( Q_strcmp( ent->GetClassname(), "class C_ParticleSmokeGrenade" ) == 0 )
  2976. {
  2977. Q_strncpy( errorMsg, "Cannot record demos while a smoke grenade is active.", length );
  2978. return false;
  2979. }
  2980. }
  2981. return true;
  2982. }
  2983. void ClientModeCSNormal::SetBlurFade( float scale )
  2984. {
  2985. }
  2986. void ClientModeCSNormal::DoPostScreenSpaceEffects( const CViewSetup *pSetup )
  2987. {
  2988. GlowObjectManager().RenderGlowEffects( pSetup, GetSplitScreenPlayerSlot() );
  2989. }
  2990. void ClientModeCSNormal::SetServerName( wchar_t *name )
  2991. {
  2992. V_wcsncpy( m_pServerName, name, sizeof( m_pServerName ) );
  2993. }
  2994. void ClientModeCSNormal::SetMapName( wchar_t *name )
  2995. {
  2996. V_wcsncpy( m_pMapName, name, sizeof( m_pMapName ) );
  2997. }
  2998. // Receive the PlayerIgnited user message and send out a clientside event for achievements to hook.
  2999. bool __MsgFunc_MatchEndConditions( const CCSUsrMsg_MatchEndConditions &msg )
  3000. {
  3001. int iFragLimit = (int) msg.fraglimit();
  3002. int iMaxRounds = (int) msg.mp_maxrounds();
  3003. int iWinRounds = (int) msg.mp_winlimit();
  3004. int iTimeLimit = (int) msg.mp_timelimit();
  3005. IGameEvent *event = gameeventmanager->CreateEvent( "match_end_conditions" );
  3006. if ( event )
  3007. {
  3008. event->SetInt( "frags", iFragLimit );
  3009. event->SetInt( "max_rounds", iMaxRounds );
  3010. event->SetInt( "win_rounds", iWinRounds );
  3011. event->SetInt( "time", iTimeLimit );
  3012. gameeventmanager->FireEventClientSide( event );
  3013. }
  3014. return true;
  3015. }
  3016. bool __MsgFunc_ServerRankUpdate( const CCSUsrMsg_ServerRankUpdate &msg )
  3017. {
  3018. /* Removed for partner depot */
  3019. return true;
  3020. }
  3021. bool __MsgFunc_ServerRankRevealAll( const CCSUsrMsg_ServerRankRevealAll &msg )
  3022. {
  3023. /* Removed for partner depot */
  3024. return true;
  3025. }
  3026. //-----------------------------------------------------------------------------
  3027. bool __MsgFunc_DisconnectToLobby( const CCSUsrMsg_DisconnectToLobby &msg )
  3028. {
  3029. if ( engine->GetDemoPlaybackParameters() )
  3030. {
  3031. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnDemoFileEndReached" ) );
  3032. g_pMatchFramework->CloseSession();
  3033. }
  3034. else
  3035. {
  3036. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  3037. "OnEngineEndGame", "reason", "gameover" ) );
  3038. }
  3039. return true;
  3040. }
  3041. bool __MsgFunc_WarmupHasEnded( const CCSUsrMsg_WarmupHasEnded &msg )
  3042. {
  3043. if ( CSGameRules() && CSGameRules()->IsQueuedMatchmaking() )
  3044. {
  3045. IViewPortPanel *pTextWindow = GetViewPortInterface()->FindPanelByName( PANEL_INFO );
  3046. if ( pTextWindow && pTextWindow->IsVisible() )
  3047. {
  3048. ( static_cast< vgui::Frame * >( ( CTextWindow * )pTextWindow ) )->OnCommand( "okay" );
  3049. }
  3050. }
  3051. return true;
  3052. }
  3053. //-----------------------------------------------------------------------------
  3054. // Purpose:
  3055. //-----------------------------------------------------------------------------
  3056. bool __MsgFunc_GlowPropTurnOff( const CCSUsrMsg_GlowPropTurnOff &msg )
  3057. {
  3058. CDynamicProp *pProp = dynamic_cast<CDynamicProp*>( ClientEntityList().GetEnt( msg.entidx() ) );
  3059. if ( pProp )
  3060. pProp->ForceTurnOffGlow();
  3061. return true;
  3062. }
  3063. bool __MsgFunc_XpUpdate( const CCSUsrMsg_XpUpdate &msg )
  3064. {
  3065. /* Removed for partner depot */
  3066. return true;
  3067. }
  3068. CUtlMap< uint32, ClientModeCSNormal::CQuestUncommittedProgress_t, uint32, CDefLess< uint32 > > ClientModeCSNormal::sm_mapQuestProgressUncommitted;
  3069. bool __MsgFunc_QuestProgress( const CCSUsrMsg_QuestProgress &msg )
  3070. {
  3071. uint32 uidxMap = ClientModeCSNormal::sm_mapQuestProgressUncommitted.Find( msg.quest_id() );
  3072. if ( uidxMap == ClientModeCSNormal::sm_mapQuestProgressUncommitted.InvalidIndex() )
  3073. {
  3074. ClientModeCSNormal::CQuestUncommittedProgress_t questProgressDefault;
  3075. V_memset( &questProgressDefault, 0, sizeof( questProgressDefault ) );
  3076. uidxMap = ClientModeCSNormal::sm_mapQuestProgressUncommitted.InsertOrReplace( msg.quest_id(), questProgressDefault );
  3077. }
  3078. ClientModeCSNormal::CQuestUncommittedProgress_t &questProgress = ClientModeCSNormal::sm_mapQuestProgressUncommitted.Element( uidxMap );
  3079. if ( msg.normal_points() > questProgress.m_numNormalPoints )
  3080. {
  3081. if ( !questProgress.m_dblNormalPointsProgressTime )
  3082. questProgress.m_numNormalPointsProgressBaseline = questProgress.m_numNormalPoints;
  3083. questProgress.m_dblNormalPointsProgressTime = Plat_FloatTime();
  3084. }
  3085. questProgress.m_bIsEventQuest = msg.is_event_quest();
  3086. questProgress.m_numNormalPoints = msg.normal_points();
  3087. return true;
  3088. }
  3089. ScoreLeaderboardData ClientModeCSNormal::s_ScoreLeaderboardData;
  3090. bool __MsgFunc_ScoreLeaderboardData( const CCSUsrMsg_ScoreLeaderboardData &msg )
  3091. {
  3092. ClientModeCSNormal::s_ScoreLeaderboardData.Clear();
  3093. if ( msg.has_data() )
  3094. ClientModeCSNormal::s_ScoreLeaderboardData.CopyFrom( msg.data() );
  3095. return true;
  3096. }
  3097. bool __MsgFunc_PlayerDecalDigitalSignature( const CCSUsrMsg_PlayerDecalDigitalSignature &msg )
  3098. {
  3099. // Game server requests us to make a digital signature for the message that we requested
  3100. if ( s_flLastDigitalSignatureTime )
  3101. {
  3102. uint64 uiNow = Plat_FloatTime();
  3103. if ( uiNow == s_flLastDigitalSignatureTime )
  3104. return true; // ignore servers that are trying to guess the trace ID
  3105. }
  3106. s_flLastDigitalSignatureTime = Plat_FloatTime();
  3107. // Find the trace ID that server is referring to
  3108. int idx = s_mapClientDigitalSignatureRequests.Find( msg.data().trace_id() );
  3109. if ( idx == s_mapClientDigitalSignatureRequests.InvalidIndex() )
  3110. return true;
  3111. PlayerSprayClientRequestData_t data = s_mapClientDigitalSignatureRequests.Element( idx );
  3112. s_mapClientDigitalSignatureRequests.RemoveAt( idx );
  3113. static CSteamID s_mysteamid = steamapicontext->SteamUser()->GetSteamID();
  3114. // Ensure that creation time is within reasonable range from when it was requested
  3115. // and all the fields match
  3116. if ( s_mysteamid.GetAccountID() != msg.data().accountid() ) return true;
  3117. if ( data.m_nEquipSlot != msg.data().equipslot() ) return true;
  3118. if ( data.m_nDefIdx != msg.data().tx_defidx() ) return true;
  3119. if ( data.m_unTintID != msg.data().tint_id() ) return true;
  3120. if ( fabs( gpGlobals->curtime - data.m_flCreationTime ) > 10 ) return true;
  3121. if ( fabs( gpGlobals->curtime - msg.data().creationtime() ) > 10 ) return true;
  3122. // Ensure that the decal to spray is around where our local player is? (grace margins due to networking delays)
  3123. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  3124. Vector vecCheck;
  3125. if ( !pLocalPlayer ) return true;
  3126. if ( msg.data().startpos_size() != 3 ) return true;
  3127. vecCheck.Init( msg.data().startpos( 0 ), msg.data().startpos( 1 ), msg.data().startpos( 2 ) );
  3128. if ( pLocalPlayer->EyePosition().DistToSqr( vecCheck ) > 128*128 ) return true;
  3129. if ( msg.data().endpos_size() != 3 ) return true;
  3130. vecCheck.Init( msg.data().endpos( 0 ), msg.data().endpos( 1 ), msg.data().endpos( 2 ) );
  3131. if ( pLocalPlayer->EyePosition().DistToSqr( vecCheck ) > 256*256 ) return true;
  3132. //
  3133. // Validate our inventory again so that we could request charge consumption from GC
  3134. //
  3135. CCSPlayerInventory* pPlayerInv = CSInventoryManager()->GetLocalCSInventory();
  3136. if ( !pPlayerInv )
  3137. return true;
  3138. CEconItemView* pEconItem = pPlayerInv->GetItemInLoadout( 0, LOADOUT_POSITION_SPRAY0 + data.m_nEquipSlot );
  3139. if ( !pEconItem || !pEconItem->IsValid() )
  3140. return true;
  3141. uint32 unStickerKitID = pEconItem->GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 );
  3142. if ( !unStickerKitID )
  3143. return true;
  3144. if ( unStickerKitID != data.m_nDefIdx )
  3145. return true;
  3146. static CSchemaAttributeDefHandle hAttrSprayTintID( "spray tint id" );
  3147. uint32 unTintID = 0;
  3148. if ( !hAttrSprayTintID || !pEconItem->FindAttribute( hAttrSprayTintID, &unTintID ) )
  3149. unTintID = 0;
  3150. if ( unTintID != data.m_unTintID )
  3151. return true;
  3152. // Record our spray into OGS:
  3153. g_CSClientGameStats.AddClientCSGOGameEvent( k_CSClientCsgoGameEventType_SprayApplication, vecCheck, pLocalPlayer->EyeAngles(), ( uint64( unStickerKitID ) << 32 ) | uint64( unTintID ) );
  3154. #ifdef _DEBUG
  3155. DevMsg( "Client decal signature (%llu) @(%.2f,%.2f,%.2f) T%u requested\n", cl2gc.Body().itemid(),
  3156. msg.data().endpos( 0 ), msg.data().endpos( 1 ), msg.data().endpos( 2 ), msg.data().rtime() );
  3157. #endif
  3158. return true;
  3159. }
  3160. class ClientJob_EMsgGCCStrike15_v2_ClientPlayerDecalSign : public GCSDK::CGCClientJob
  3161. {
  3162. public:
  3163. explicit ClientJob_EMsgGCCStrike15_v2_ClientPlayerDecalSign( GCSDK::CGCClient *pGCClient ) : GCSDK::CGCClientJob( pGCClient )
  3164. {
  3165. }
  3166. virtual bool BYieldingRunJobFromMsg( GCSDK::IMsgNetPacket *pNetPacket )
  3167. {
  3168. GCSDK::CProtoBufMsg<CMsgGCCStrike15_v2_ClientPlayerDecalSign> msg( pNetPacket );
  3169. #ifdef _DEBUG
  3170. DevMsg( "Client decal signature (%llu) T%u = [%u b]\n", msg.Body().itemid(),
  3171. msg.Body().data().rtime(), msg.Body().data().signature().size() );
  3172. #endif
  3173. if ( !msg.Body().data().signature().size() )
  3174. return false;
  3175. if ( !BValidateClientPlayerDecalSignature( msg.Body().data() ) )
  3176. return false;
  3177. CSVCMsg_UserMessage_t um;
  3178. CCSUsrMsg_PlayerDecalDigitalSignature gameMsg;
  3179. gameMsg.mutable_data()->CopyFrom( msg.Body().data() );
  3180. if ( BSerializeUserMessageToSVCMSG( um, CS_UM_PlayerDecalDigitalSignature, gameMsg ) )
  3181. engine->SendMessageToServer( &um );
  3182. return true;
  3183. }
  3184. };
  3185. GC_REG_CLIENT_JOB( ClientJob_EMsgGCCStrike15_v2_ClientPlayerDecalSign, k_EMsgGCCStrike15_v2_ClientPlayerDecalSign );
  3186. void PlayerDecalDataSendActionSprayToServer( int nSlot )
  3187. {
  3188. CCSPlayerInventory* pPlayerInv = CSInventoryManager()->GetLocalCSInventory();
  3189. if ( !pPlayerInv )
  3190. return;
  3191. CEconItemView* pEconItem = pPlayerInv->GetItemInLoadout( 0, LOADOUT_POSITION_SPRAY0 + nSlot );
  3192. if ( !pEconItem || !pEconItem->IsValid() )
  3193. return;
  3194. uint32 unStickerKitID = pEconItem->GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 );
  3195. if ( !unStickerKitID )
  3196. return;
  3197. static CSchemaAttributeDefHandle hAttrSprayTintID( "spray tint id" );
  3198. int nRandomKey = RandomInt( 2, INT_MAX/2 );
  3199. PlayerSprayClientRequestData_t data;
  3200. data.m_nEquipSlot = nSlot;
  3201. data.m_nDefIdx = unStickerKitID;
  3202. if ( !hAttrSprayTintID || !pEconItem->FindAttribute( hAttrSprayTintID, &data.m_unTintID ) )
  3203. data.m_unTintID = 0;
  3204. data.m_flCreationTime = gpGlobals->curtime;
  3205. s_flLastDigitalSignatureTime = 0;
  3206. s_mapClientDigitalSignatureRequests.RemoveAll();
  3207. s_mapClientDigitalSignatureRequests.InsertOrReplace( nRandomKey, data );
  3208. static CSteamID s_mysteamid = steamapicontext->SteamUser()->GetSteamID();
  3209. CCSUsrMsg_PlayerDecalDigitalSignature msg;
  3210. PlayerDecalDigitalSignature &dd = *msg.mutable_data();
  3211. dd.set_accountid( s_mysteamid.GetAccountID() );
  3212. dd.set_equipslot( data.m_nEquipSlot );
  3213. dd.set_tx_defidx( data.m_nDefIdx );
  3214. dd.set_tint_id( data.m_unTintID );
  3215. dd.set_creationtime( data.m_flCreationTime );
  3216. dd.set_trace_id( nRandomKey );
  3217. CSVCMsg_UserMessage_t um;
  3218. if ( BSerializeUserMessageToSVCMSG( um, CS_UM_PlayerDecalDigitalSignature, msg ) )
  3219. engine->SendMessageToServer( &um );
  3220. }
  3221. void ClientModeCSFullscreen::Init( void )
  3222. {
  3223. BaseClass::Init();
  3224. ListenForGameEvent( "smokegrenade_detonate" );
  3225. ListenForGameEvent( "smokegrenade_expired" );
  3226. }
  3227. bool g_bClientIsAllowedToPlayOnSecureServers = true;
  3228. CEG_NOINLINE void ClientModeCSFullscreen::OnEvent( KeyValues *pEvent )
  3229. {
  3230. BaseClass::OnEvent( pEvent );
  3231. const char *pEventName = pEvent->GetName();
  3232. if ( !Q_stricmp( pEventName, "OnEngineDisconnectReason" ) )
  3233. {
  3234. DevMsg( "ClientModeCSNormal::OnEvent" );
  3235. KeyValuesDumpAsDevMsg( pEvent, 1 );
  3236. char const *szReason = pEvent->GetString( "reason", "" );
  3237. if ( char const *szDisconnectHdlr = pEvent->GetString( "disconnecthdlr", NULL ) )
  3238. {
  3239. // If a disconnect handler was set during the event, then we don't interfere with
  3240. // the dialog explaining disconnection, just let the disconnect handler do everything.
  3241. return;
  3242. }
  3243. // Display the disconnection reason.
  3244. RemapText_t arrText[] = {
  3245. { "", "#SFUI_DisconnectReason_Unknown", RemapText_t::MATCH_FULL },
  3246. { "Lost connection to LIVE", "#SFUI_DisconnectReason_LostConnectionToLIVE", RemapText_t::MATCH_FULL },
  3247. { "For killing too many teammates", "#SFUI_DisconnectReason_TeamKilling", RemapText_t::MATCH_SUBSTR },
  3248. { "For killing a teammate at round start", "#SFUI_SessionError_KickBan_TK_Start", RemapText_t::MATCH_SUBSTR },
  3249. { "Account is Untrusted", "#SFUI_DisconnectReason_OfficialBan", RemapText_t::MATCH_SUBSTR },
  3250. { "Account is Convicted", "#SFUI_DisconnectReason_Convicted", RemapText_t::MATCH_SUBSTR },
  3251. { "Player has competitive matchmaking cooldown", "#SFUI_DisconnectReason_CompetitiveCooldown", RemapText_t::MATCH_SUBSTR },
  3252. { "For doing too much team damage", "#SFUI_DisconnectReason_TeamHurting", RemapText_t::MATCH_SUBSTR },
  3253. { "For killing too many hostages", "#SFUI_SessionError_Kicked", RemapText_t::MATCH_SUBSTR },
  3254. { "Player removed from host session", "#SFUI_DisconnectReason_PlayerRemovedFromSession", RemapText_t::MATCH_SUBSTR },
  3255. { "Connection to server timed out", "#SFUI_DisconnectReason_DisconnectedFromServer", RemapText_t::MATCH_SUBSTR },
  3256. { "Server shutting down", "#SFUI_DisconnectReason_DisconnectedServerShuttingDown", RemapText_t::MATCH_SUBSTR },
  3257. { "Added to banned list", "#SFUI_SessionError_Kicked", RemapText_t::MATCH_SUBSTR },
  3258. { "Kicked and banned", "#SFUI_SessionError_Kicked", RemapText_t::MATCH_SUBSTR },
  3259. { "You have been voted off", "#SFUI_SessionError_Kicked", RemapText_t::MATCH_SUBSTR },
  3260. { "VAC authentication error", "#SFUI_DisconnectReason_VAC", RemapText_t::MATCH_SUBSTR },
  3261. { "Player idle", "#SFUI_DisconnectReason_Idle", RemapText_t::MATCH_SUBSTR },
  3262. { "For suiciding too many times", "#SFUI_DisconnectionReason_Suicide", RemapText_t::MATCH_SUBSTR },
  3263. { "You must use matchmaking to connect to this CS:GO server", "#SFUI_DisconnectReason_MustUseMatchmaking", RemapText_t::MATCH_SUBSTR },
  3264. { "You cannot connect to this CS:GO server because it is restricted to LAN connections only", "#SFUI_DisconnectReason_ServerLanRestricted", RemapText_t::MATCH_SUBSTR },
  3265. { "Kicked by", "#SFUI_SessionError_Kicked", RemapText_t::MATCH_SUBSTR }, // Since many strings include "kicked by", insert messages above this one
  3266. #ifdef _GAMECONSOLE
  3267. { "", "#SFUI_DisconnectReason_Unknown", RemapText_t::MATCH_START }, // Catch all cases for X360
  3268. #endif
  3269. { NULL, NULL, RemapText_t::MATCH_FULL }
  3270. };
  3271. // For any disconnection reason other than unknown:
  3272. if ( szReason && !StringHasPrefix( szReason, "#SFUI_DisconnectReason_Unknown" ) )
  3273. {
  3274. STEAMWORKS_SELFCHECK();
  3275. }
  3276. szReason = RemapText_t::RemapRawText( arrText, szReason );
  3277. const char *okCommand = NULL;
  3278. if ( !V_strcmp( szReason, "#SFUI_DisconnectReason_VAC" ) )
  3279. okCommand = "error_message_explain_vac";
  3280. else if ( !V_strcmp( szReason, "#GameUI_Disconnect_PureServer_Mismatch" ) )
  3281. okCommand = "error_message_explain_pure";
  3282. CCommandMsgBox::CreateAndShow("#SFUI_Disconnect_Title", szReason, true, false, okCommand );
  3283. }
  3284. else if ( !Q_stricmp( pEventName, "OnClientInsecureBlocked" ) )
  3285. {
  3286. STEAMWORKS_SELFCHECK();
  3287. g_bClientIsAllowedToPlayOnSecureServers = false;
  3288. CMessageBoxScaleform::UnloadAllDialogs();
  3289. BasePanel()->RestoreMainMenuScreen();
  3290. char const *szSuffix = "";
  3291. if ( ( CommandLine()->FindParm( "-insecure" ) && !CommandLine()->FindParm( "-insecure_forced_by_launcher" ) ) || CommandLine()->FindParm( "-tools" ) )
  3292. szSuffix = "_cmd";
  3293. CCommandMsgBox::CreateAndShow( CFmtStr( "#SFUI_DisconnectReason_OnClientInsecureTitle_%s", pEvent->GetString( "reason" ) ),
  3294. CFmtStr( "#SFUI_DisconnectReason_OnClientInsecureBlocked_%s%s", pEvent->GetString( "reason" ), szSuffix ), true);
  3295. }
  3296. }
  3297. CON_COMMAND_F( error_message_explain_vac, "Take user to Steam support article", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_HIDDEN )
  3298. {
  3299. vgui::system()->ShellExecute( "open", "https://support.steampowered.com/kb_article.php?ref=2117-ILZV-2837" );
  3300. }
  3301. CON_COMMAND_F( error_message_explain_pure, "Take user to Steam support article", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_HIDDEN )
  3302. {
  3303. vgui::system()->ShellExecute( "open", "https://support.steampowered.com/kb_article.php?ref=8285-YOAZ-6049" );
  3304. }
  3305. void ClientModeCSFullscreen::FireGameEvent( IGameEvent *event )
  3306. {
  3307. const char *eventname = event->GetName();
  3308. if ( !eventname || !eventname[0] )
  3309. return;
  3310. if ( Q_strcmp( "tr_show_finish_msgbox", eventname ) == 0 )
  3311. {
  3312. GameUI().CreateCommandMsgBoxInSlot(
  3313. CMB_SLOT_PLAYER_0,
  3314. "#TR_Finish_All_MsgBox_Title",
  3315. "#TR_Finish_All_MsgBox_Body",
  3316. true,
  3317. false,
  3318. "disconnect\n",
  3319. NULL,
  3320. NULL,
  3321. NULL );
  3322. }
  3323. else if ( Q_strcmp( "tr_show_exit_msgbox", eventname ) == 0 )
  3324. {
  3325. GameUI().CreateCommandMsgBoxInSlot(
  3326. CMB_SLOT_PLAYER_0,
  3327. "#TR_ExitDoor_MsgBox_Title",
  3328. "#TR_ExitDoor_MsgBox_Body",
  3329. true,
  3330. true,
  3331. "tr_map_show_exit_door_msg",
  3332. NULL,
  3333. NULL,
  3334. NULL );
  3335. }
  3336. else if ( V_strcmp( "smokegrenade_detonate", eventname ) == 0 )
  3337. {
  3338. Vector v;
  3339. v.x = event->GetFloat( "X" );
  3340. v.y = event->GetFloat( "Y" );
  3341. v.z = event->GetFloat( "Z" );
  3342. FirePerfStatsEvent( PERF_STATS_SMOKE );
  3343. int index = event->GetInt( "entityid" );
  3344. C_BaseEntity* pEnt = ClientEntityList().GetBaseEntity( index );
  3345. if ( pEnt )
  3346. AddSmokeGrenadeHandle( pEnt );
  3347. }
  3348. else if ( V_strcmp( "smokegrenade_expired", eventname ) == 0 )
  3349. {
  3350. Vector v;
  3351. v.x = event->GetFloat( "X" );
  3352. v.y = event->GetFloat( "Y" );
  3353. v.z = event->GetFloat( "Z" );
  3354. int index = event->GetInt( "entityid" );
  3355. C_BaseEntity* pEnt = ClientEntityList().GetBaseEntity( index );
  3356. if ( pEnt )
  3357. RemoveSmokeGrenadeHandle( pEnt );
  3358. }
  3359. else if ( V_strcmp( "round_start", eventname ) == 0 )
  3360. {
  3361. // empty the client side list of smoke grenade locations
  3362. RemoveAllSmokeGrenades();
  3363. BaseClass::FireGameEvent( event );
  3364. }
  3365. else if ( V_strcmp( "game_newmap", eventname ) == 0 )
  3366. {
  3367. RemoveAllSmokeGrenades();
  3368. }
  3369. else
  3370. {
  3371. BaseClass::FireGameEvent( event );
  3372. }
  3373. }