Team Fortress 2 Source Code as on 22/4/2020
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.

556 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include "hud.h"
  10. #include "clientmode_dod.h"
  11. #include "cdll_client_int.h"
  12. #include "iinput.h"
  13. #include "vgui/ISurface.h"
  14. #include "vgui/IPanel.h"
  15. #include <vgui_controls/AnimationController.h>
  16. #include "ivmodemanager.h"
  17. #include "buymenu.h"
  18. #include "filesystem.h"
  19. #include "vgui/IVGui.h"
  20. #include "hud_basechat.h"
  21. #include "view_shared.h"
  22. #include "view.h"
  23. #include "ivrenderview.h"
  24. #include "model_types.h"
  25. #include "iefx.h"
  26. #include "dlight.h"
  27. #include <imapoverview.h>
  28. #include "c_playerresource.h"
  29. #include <KeyValues.h>
  30. #include "text_message.h"
  31. #include "panelmetaclassmgr.h"
  32. #include "dod_shareddefs.h"
  33. #include "c_dod_player.h"
  34. #include "physpropclientside.h"
  35. #include "engine/IEngineSound.h"
  36. #include "bitbuf.h"
  37. #include "usermessages.h"
  38. #include "prediction.h"
  39. #include "vgui/ILocalize.h"
  40. #include "dod_hud_freezepanel.h"
  41. #include "dod_hud_chat.h"
  42. // memdbgon must be the last include file in a .cpp file!!!
  43. #include "tier0/memdbgon.h"
  44. class CHudChat;
  45. ConVar default_fov( "default_fov", "90", FCVAR_CHEAT );
  46. ConVar dod_playwinmusic( "dod_playwinmusic", "1", FCVAR_ARCHIVE );
  47. IClientMode *g_pClientMode = NULL;
  48. void MsgFunc_KillCam(bf_read &msg)
  49. {
  50. C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  51. if ( !pPlayer )
  52. return;
  53. int newMode = msg.ReadByte();
  54. if ( newMode != g_nKillCamMode )
  55. {
  56. #if !defined( NO_ENTITY_PREDICTION )
  57. if ( g_nKillCamMode == OBS_MODE_NONE )
  58. {
  59. // kill cam is switch on, turn off prediction
  60. g_bForceCLPredictOff = true;
  61. }
  62. else if ( newMode == OBS_MODE_NONE )
  63. {
  64. // kill cam is switched off, restore old prediction setting is we switch back to normal mode
  65. g_bForceCLPredictOff = false;
  66. }
  67. #endif
  68. g_nKillCamMode = newMode;
  69. }
  70. g_nKillCamTarget1 = msg.ReadByte();
  71. g_nKillCamTarget2 = msg.ReadByte();
  72. }
  73. // --------------------------------------------------------------------------------- //
  74. // CDODModeManager.
  75. // --------------------------------------------------------------------------------- //
  76. class CDODModeManager : public IVModeManager
  77. {
  78. public:
  79. virtual void Init();
  80. virtual void SwitchMode( bool commander, bool force ) {}
  81. virtual void LevelInit( const char *newmap );
  82. virtual void LevelShutdown( void );
  83. virtual void ActivateMouse( bool isactive ) {}
  84. };
  85. static CDODModeManager g_ModeManager;
  86. IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager;
  87. // --------------------------------------------------------------------------------- //
  88. // CDODModeManager implementation.
  89. // --------------------------------------------------------------------------------- //
  90. #define SCREEN_FILE "scripts/vgui_screens.txt"
  91. void CDODModeManager::Init()
  92. {
  93. g_pClientMode = GetClientModeNormal();
  94. PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
  95. }
  96. void CDODModeManager::LevelInit( const char *newmap )
  97. {
  98. g_pClientMode->LevelInit( newmap );
  99. #if !defined( NO_ENTITY_PREDICTION )
  100. if ( g_nKillCamMode > OBS_MODE_NONE )
  101. {
  102. g_bForceCLPredictOff = false;
  103. }
  104. #endif
  105. g_nKillCamMode = OBS_MODE_NONE;
  106. g_nKillCamTarget1 = 0;
  107. g_nKillCamTarget2 = 0;
  108. }
  109. void CDODModeManager::LevelShutdown( void )
  110. {
  111. g_pClientMode->LevelShutdown();
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose:
  115. //-----------------------------------------------------------------------------
  116. ClientModeDODNormal::ClientModeDODNormal()
  117. {
  118. m_pFreezePanel = NULL;
  119. }
  120. void ClientModeDODNormal::Init()
  121. {
  122. BaseClass::Init();
  123. ListenForGameEvent( "dod_round_start" );
  124. ListenForGameEvent( "dod_broadcast_audio" );
  125. ListenForGameEvent( "player_team" );
  126. ListenForGameEvent( "dod_bomb_planted" );
  127. ListenForGameEvent( "dod_bomb_defused" );
  128. ListenForGameEvent( "dod_timer_flash" );
  129. usermessages->HookMessage( "KillCam", MsgFunc_KillCam );
  130. m_szLastRadioSound[0] = '\0';
  131. m_pFreezePanel = ( CDODFreezePanel * )GET_HUDELEMENT( CDODFreezePanel );
  132. Assert( m_pFreezePanel );
  133. }
  134. void ClientModeDODNormal::InitViewport()
  135. {
  136. m_pViewport = new DODViewport();
  137. m_pViewport->Start( gameuifuncs, gameeventmanager );
  138. }
  139. ClientModeDODNormal g_ClientModeNormal;
  140. IClientMode *GetClientModeNormal()
  141. {
  142. return &g_ClientModeNormal;
  143. }
  144. ClientModeDODNormal* GetClientModeDODNormal()
  145. {
  146. Assert( dynamic_cast< ClientModeDODNormal* >( GetClientModeNormal() ) );
  147. return static_cast< ClientModeDODNormal* >( GetClientModeNormal() );
  148. }
  149. ConVar r_viewmodelfov( "r_viewmodelfov", "0", FCVAR_CHEAT );
  150. float ClientModeDODNormal::GetViewModelFOV( void )
  151. {
  152. float flFov = 90.0f;
  153. if( r_viewmodelfov.GetFloat() > 0 )
  154. return r_viewmodelfov.GetFloat();
  155. C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  156. if( !pPlayer )
  157. return flFov;
  158. CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();
  159. if( pWpn )
  160. {
  161. flFov = pWpn->GetDODWpnData().m_flViewModelFOV;
  162. }
  163. return flFov;
  164. }
  165. int ClientModeDODNormal::GetDeathMessageStartHeight( void )
  166. {
  167. return m_pViewport->GetDeathMessageStartHeight();
  168. }
  169. void ClientModeDODNormal::FireGameEvent( IGameEvent * event)
  170. {
  171. const char *eventname = event->GetName();
  172. if ( !eventname || !eventname[0] )
  173. return;
  174. if ( Q_strcmp( "dod_round_start", eventname ) == 0 )
  175. {
  176. // Just tell engine to clear decals
  177. engine->ClientCmd( "r_cleardecals\n" );
  178. // recreate all client side physics props
  179. // check for physenv, because we sometimes crash on changelevel
  180. // if we get this message before fully connecting
  181. if ( physenv )
  182. {
  183. C_PhysPropClientside::RecreateAll();
  184. }
  185. }
  186. else if( Q_strcmp( "dod_broadcast_audio", eventname ) == 0 )
  187. {
  188. CLocalPlayerFilter filter;
  189. const char *pszSoundName = event->GetString("sound");
  190. if ( dod_playwinmusic.GetBool() == false )
  191. {
  192. if ( FStrEq( pszSoundName, "Game.USWin" ) || FStrEq( pszSoundName, "Game.GermanWin" ) )
  193. {
  194. return;
  195. }
  196. }
  197. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName );
  198. }
  199. else if ( Q_strcmp( "dod_bomb_planted", eventname ) == 0 )
  200. {
  201. int defendingTeam = event->GetInt( "team" );
  202. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  203. if ( !pLocalPlayer )
  204. return;
  205. const char *pszSound = "";
  206. const char *pszMessage = "";
  207. int localTeam = pLocalPlayer->GetTeamNumber();
  208. const char *pPlanterName = NULL;
  209. int iPlanterIndex = 0;
  210. if ( defendingTeam == localTeam )
  211. {
  212. // play defend sound
  213. switch( localTeam )
  214. {
  215. case TEAM_ALLIES:
  216. {
  217. pszSound = "Voice.US_C4EnemyPlanted";
  218. pszMessage = "#dod_bomb_us_enemy_planted";
  219. }
  220. break;
  221. case TEAM_AXIS:
  222. {
  223. pszSound = "Voice.German_C4EnemyPlanted";
  224. pszMessage = "#dod_bomb_ger_enemy_planted";
  225. }
  226. break;
  227. default:
  228. break;
  229. }
  230. }
  231. else
  232. {
  233. // play planting sound
  234. switch( localTeam )
  235. {
  236. case TEAM_ALLIES:
  237. {
  238. pszSound = "Voice.US_C4TeamPlanted";
  239. pszMessage = "#dod_bomb_us_team_planted";
  240. }
  241. break;
  242. case TEAM_AXIS:
  243. {
  244. pszSound = "Voice.German_C4TeamPlanted";
  245. pszMessage = "#dod_bomb_ger_team_planted";
  246. }
  247. break;
  248. default:
  249. break;
  250. }
  251. // Only show the planter name if its a team plant, not enemy plant
  252. iPlanterIndex = engine->GetPlayerForUserID( event->GetInt("userid") );
  253. pPlanterName = g_PR->GetPlayerName( iPlanterIndex );
  254. }
  255. RadioMessage( pszSound, pszMessage, pPlanterName, iPlanterIndex );
  256. }
  257. else if ( Q_strcmp( "dod_bomb_defused", eventname ) == 0 )
  258. {
  259. int defusingTeam = event->GetInt( "team" );
  260. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  261. if ( !pLocalPlayer )
  262. return;
  263. const char *pszSound = "";
  264. const char *pszMessage = "";
  265. int localTeam = pLocalPlayer->GetTeamNumber();
  266. if ( defusingTeam == localTeam )
  267. {
  268. // play defused sound
  269. switch( localTeam )
  270. {
  271. case TEAM_ALLIES:
  272. {
  273. pszSound = "Voice.US_C4Defused";
  274. pszMessage = "#dod_bomb_us_defused";
  275. }
  276. break;
  277. case TEAM_AXIS:
  278. {
  279. pszSound = "Voice.German_C4Defused";
  280. pszMessage = "#dod_bomb_ger_defused";
  281. }
  282. break;
  283. default:
  284. break;
  285. }
  286. int iDefuser = engine->GetPlayerForUserID( event->GetInt("userid") );
  287. const char *pDefuserName = g_PR->GetPlayerName( iDefuser );
  288. RadioMessage( pszSound, pszMessage, pDefuserName, iDefuser );
  289. }
  290. }
  291. else if ( Q_strcmp( "player_team", eventname ) == 0 )
  292. {
  293. C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
  294. if ( !pPlayer )
  295. return;
  296. bool bDisconnected = event->GetBool("disconnect");
  297. if ( bDisconnected )
  298. return;
  299. int team = event->GetInt( "team" );
  300. if ( pPlayer->IsLocalPlayer() )
  301. {
  302. // that's me
  303. pPlayer->TeamChange( team );
  304. }
  305. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  306. if ( !hudChat )
  307. return;
  308. const char *pTemplate = NULL;
  309. if ( team == TEAM_ALLIES )
  310. {
  311. pTemplate = "#game_joined_allies";
  312. }
  313. else if ( team == TEAM_AXIS )
  314. {
  315. pTemplate = "#game_joined_axis";
  316. }
  317. else
  318. {
  319. pTemplate = "#game_joined_spectators";
  320. }
  321. wchar_t szPlayerName[MAX_PLAYER_NAME_LENGTH];
  322. g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), szPlayerName, sizeof(szPlayerName) );
  323. wchar_t wszPrint[128];
  324. char szPrint[128];
  325. g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pTemplate), 1, szPlayerName );
  326. g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) );
  327. hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s",szPrint );
  328. }
  329. else if ( Q_strcmp( "dod_timer_flash", eventname ) == 0 )
  330. {
  331. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  332. if ( !pLocalPlayer )
  333. return;
  334. const char *pszSound = "";
  335. const char *pszMessage = "";
  336. int localTeam = pLocalPlayer->GetTeamNumber();
  337. int iTimeRemaining = event->GetInt( "time_remaining", 0 );
  338. switch( iTimeRemaining )
  339. {
  340. case 60:
  341. switch( localTeam )
  342. {
  343. case TEAM_ALLIES:
  344. {
  345. pszSound = "Voice.US_OneMinute";
  346. pszMessage = "#dod_time_remaining_us_1_min";
  347. }
  348. break;
  349. case TEAM_AXIS:
  350. {
  351. pszSound = "Voice.German_OneMinute";
  352. pszMessage = "#dod_time_remaining_ger_1_min";
  353. }
  354. break;
  355. default:
  356. break;
  357. }
  358. break;
  359. case 120:
  360. switch( localTeam )
  361. {
  362. case TEAM_ALLIES:
  363. {
  364. pszSound = "Voice.US_TwoMinute";
  365. pszMessage = "#dod_time_remaining_us_2_min";
  366. }
  367. break;
  368. case TEAM_AXIS:
  369. {
  370. pszSound = "Voice.German_TwoMinute";
  371. pszMessage = "#dod_time_remaining_ger_2_min";
  372. }
  373. break;
  374. default:
  375. break;
  376. }
  377. break;
  378. default:
  379. break;
  380. }
  381. RadioMessage( pszSound, pszMessage );
  382. }
  383. else
  384. BaseClass::FireGameEvent( event );
  385. }
  386. void ClientModeDODNormal::PostRenderVGui()
  387. {
  388. }
  389. bool ClientModeDODNormal::ShouldDrawViewModel()
  390. {
  391. C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  392. CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();
  393. if( pWpn && pWpn->ShouldDrawViewModel() == false )
  394. {
  395. return false;
  396. }
  397. return BaseClass::ShouldDrawViewModel();
  398. }
  399. void ClientModeDODNormal::RadioMessage( const char *pszSoundName, const char *pszSubtitle, const char *pszSender /* = NULL */, int iSenderIndex /* = 0 */ )
  400. {
  401. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  402. if ( !pLocalPlayer )
  403. {
  404. return;
  405. }
  406. int color = COLOR_PLAYERNAME;
  407. // stop the last played radio message
  408. if ( Q_strlen( m_szLastRadioSound ) > 0 )
  409. {
  410. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  411. if ( pLocalPlayer )
  412. {
  413. pLocalPlayer->StopSound( m_szLastRadioSound );
  414. }
  415. }
  416. Q_strncpy( m_szLastRadioSound, pszSoundName, sizeof(m_szLastRadioSound) );
  417. // Play the radio alert
  418. char szCmd[128];
  419. Q_snprintf( szCmd, sizeof(szCmd), "playgamesound %s", pszSoundName );
  420. engine->ClientCmd( szCmd );
  421. // Print a message to chat
  422. wchar_t wszPrint[128];
  423. char szPrint[128];
  424. g_pVGuiLocalize->ConstructString( wszPrint, sizeof(wszPrint), g_pVGuiLocalize->Find(pszSubtitle), 0 );
  425. g_pVGuiLocalize->ConvertUnicodeToANSI( wszPrint, szPrint, sizeof(szPrint) );
  426. CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat );
  427. if ( !hudChat )
  428. return;
  429. wchar_t *pwLoc = g_pVGuiLocalize->Find( "#dod_radio_prefix" );
  430. char szPrefix[16];
  431. g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szPrefix, sizeof(szPrefix) );
  432. pwLoc = g_pVGuiLocalize->Find( pszSubtitle );
  433. char szSuffix[512];
  434. g_pVGuiLocalize->ConvertUnicodeToANSI( pwLoc, szSuffix, sizeof(szSuffix) );
  435. if ( pszSender )
  436. {
  437. hudChat->ChatPrintf( iSenderIndex, CHAT_FILTER_NONE, "%c%s %s %c: %s", COLOR_PLAYERNAME, szPrefix, g_PR->GetPlayerName( iSenderIndex ), COLOR_NORMAL, szSuffix );
  438. }
  439. else
  440. {
  441. hudChat->Printf( CHAT_FILTER_NONE, "%c%s %c: %s", color, szPrefix, COLOR_NORMAL, szSuffix );
  442. }
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose: See if hud elements want key input. Return 0 if the key is swallowed
  446. //-----------------------------------------------------------------------------
  447. int ClientModeDODNormal::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
  448. {
  449. if ( m_pFreezePanel )
  450. {
  451. m_pFreezePanel->HudElementKeyInput( down, keynum, pszCurrentBinding );
  452. }
  453. return BaseClass::HudElementKeyInput( down, keynum, pszCurrentBinding );
  454. }