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.

522 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include <vgui/ISurface.h>
  8. #include "clientmode_csnormal.h"
  9. #include "cs_gamerules.h"
  10. #include "hud_numericdisplay.h"
  11. #include "voice_status.h"
  12. #include "c_plantedc4.h"
  13. #include "weapon_c4.h"
  14. #include "c_cs_hostage.h"
  15. #include "c_cs_playerresource.h"
  16. #include <coordsize.h>
  17. #include "hud_macros.h"
  18. #include "vgui/IVGui.h"
  19. #include "vgui/ILocalize.h"
  20. #include "mapoverview.h"
  21. #include "cstrikespectatorgui.h"
  22. #include "hud_radar.h"
  23. #define RADAR_DOT_NORMAL 0
  24. #define RADAR_DOT_BOMB (1<<0)
  25. #define RADAR_DOT_HOSTAGE (1<<1)
  26. #define RADAR_DOT_BOMBCARRIER (1<<2)
  27. #define RADAR_DOT_VIP (1<<3)
  28. #define RADAR_DOT_LARGE_FLASH (1<<4)
  29. #define RADAR_DOT_BOMB_PLANTED (1<<5)
  30. #define RADAR_IGNORE_Z (1<<6) //always draw this item as if it was at the same Z as the player
  31. extern CUtlVector< CC4* > g_C4s;
  32. ConVar cl_radartype( "cl_radartype", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  33. ConVar cl_radaralpha( "cl_radaralpha", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, NULL, true, 0, true, 255 );
  34. ConVar cl_locationalpha( "cl_locationalpha", "150", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, NULL, true, 0, true, 255 );
  35. DECLARE_HUDELEMENT( CHudRadar );
  36. DECLARE_HUD_MESSAGE( CHudRadar, UpdateRadar );
  37. static CHudRadar *s_Radar = NULL;
  38. CUtlVector<CPlayerRadarFlash> g_RadarFlashes;
  39. CHudRadar::CHudRadar( const char *pName ) : vgui::Panel( NULL, "HudRadar" ), CHudElement( pName )
  40. {
  41. SetParent( g_pClientMode->GetViewport() );
  42. m_pBackground = NULL;
  43. m_pBackgroundTrans = NULL;
  44. m_flNextBombFlashTime = 0.0;
  45. m_bBombFlash = true;
  46. m_flNextHostageFlashTime = 0.0;
  47. m_bHostageFlash = true;
  48. m_bHideRadar = false;
  49. s_Radar = this;
  50. SetHiddenBits( HIDEHUD_PLAYERDEAD );
  51. }
  52. CHudRadar::~CHudRadar()
  53. {
  54. s_Radar = NULL;
  55. }
  56. void CHudRadar::Init()
  57. {
  58. HOOK_HUD_MESSAGE( CHudRadar, UpdateRadar );
  59. }
  60. void CHudRadar::LevelInit()
  61. {
  62. m_flNextBombFlashTime = 0.0;
  63. m_bBombFlash = true;
  64. m_flNextHostageFlashTime = 0.0;
  65. m_bHostageFlash = true;
  66. g_RadarFlashes.RemoveAll();
  67. // Map Overview handles radar duties now.
  68. if( g_pMapOverview )
  69. g_pMapOverview->SetMode(CCSMapOverview::MAP_MODE_RADAR);
  70. }
  71. void CHudRadar::Reset()
  72. {
  73. CHudElement::Reset();
  74. if( g_pMapOverview )
  75. g_pMapOverview->SetMode(CCSMapOverview::MAP_MODE_RADAR);
  76. }
  77. void CHudRadar::MsgFunc_UpdateRadar(bf_read &msg )
  78. {
  79. int iPlayerEntity = msg.ReadByte();
  80. //Draw objects on the radar
  81. //=============================
  82. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  83. if ( !pLocalPlayer )
  84. return;
  85. C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
  86. if ( !pCSPR )
  87. return;
  88. //Players
  89. for(int i=1;i<=MAX_PLAYERS;i++)
  90. {
  91. if( i == pLocalPlayer->entindex() )
  92. continue;
  93. C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex(i) );
  94. if ( pPlayer )
  95. {
  96. pPlayer->m_bDetected = false;
  97. }
  98. }
  99. while ( iPlayerEntity > 0 )
  100. {
  101. int x = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
  102. int y = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
  103. int z = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
  104. int a = msg.ReadSBitLong( 9 );
  105. C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex(iPlayerEntity) );
  106. Vector origin( x, y, z );
  107. QAngle angles( 0, a, 0 );
  108. if ( g_pMapOverview )
  109. {
  110. g_pMapOverview->SetPlayerPositions( iPlayerEntity-1, origin, angles );
  111. }
  112. iPlayerEntity = msg.ReadByte(); // read index for next player
  113. if ( !pPlayer )
  114. continue;
  115. bool bOppositeTeams = (pLocalPlayer->GetTeamNumber() != TEAM_UNASSIGNED && pCSPR->GetTeam( pPlayer->entindex() ) != pLocalPlayer->GetTeamNumber());
  116. //=============================================================================
  117. // HPE_BEGIN:
  118. // [tj] This used to do slightly different logic that caused other players
  119. // to twitch while you were observing.
  120. //=============================================================================
  121. // Don't update players if they are in PVS.
  122. if (!pPlayer->IsDormant())
  123. {
  124. continue;
  125. }
  126. //Don't update players if you are sill alive and they are an enemy.
  127. if (bOppositeTeams && !pLocalPlayer->IsObserver())
  128. {
  129. continue;
  130. }
  131. //=============================================================================
  132. // HPE_END
  133. //=============================================================================
  134. // update origin and angle for players out of my PVS
  135. origin = pPlayer->GetAbsOrigin();
  136. angles = pPlayer->GetAbsAngles();
  137. origin.x = x;
  138. origin.y = y;
  139. angles.y = a;
  140. pPlayer->SetAbsOrigin( origin );
  141. pPlayer->SetAbsAngles( angles );
  142. pPlayer->m_bDetected = true;
  143. }
  144. }
  145. bool CHudRadar::ShouldDraw()
  146. {
  147. C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
  148. //=============================================================================
  149. // HPE_BEGIN:
  150. // [tj] Added base class call
  151. //=============================================================================
  152. return pPlayer && pPlayer->IsAlive() && !m_bHideRadar && CHudElement::ShouldDraw();
  153. //=============================================================================
  154. // HPE_END
  155. //=============================================================================
  156. }
  157. void CHudRadar::SetVisible(bool state)
  158. {
  159. BaseClass::SetVisible(state);
  160. if( g_pMapOverview && g_pMapOverview->GetMode() == CCSMapOverview::MAP_MODE_RADAR )
  161. {
  162. // We are the hud element still, but he is in charge of the new style now.
  163. g_pMapOverview->SetVisible( state );
  164. }
  165. }
  166. void CHudRadar::Paint()
  167. {
  168. // We are the hud element still, but Overview is in charge of the new style now.
  169. return;
  170. }
  171. void CHudRadar::WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta )
  172. {
  173. float x_diff = location.x - origin.x;
  174. float y_diff = location.y - origin.y;
  175. int iRadarRadius = GetWide(); //width of the panel, it resizes now!
  176. float fRange = 16 * iRadarRadius; // radar's range
  177. float flOffset = atan(y_diff/x_diff);
  178. flOffset *= 180;
  179. flOffset /= M_PI;
  180. if ((x_diff < 0) && (y_diff >= 0))
  181. flOffset = 180 + flOffset;
  182. else if ((x_diff < 0) && (y_diff < 0))
  183. flOffset = 180 + flOffset;
  184. else if ((x_diff >= 0) && (y_diff < 0))
  185. flOffset = 360 + flOffset;
  186. y_diff = -1*(sqrt((x_diff)*(x_diff) + (y_diff)*(y_diff)));
  187. x_diff = 0;
  188. flOffset = angles.y - flOffset;
  189. flOffset *= M_PI;
  190. flOffset /= 180; // now theta is in radians
  191. float xnew_diff = x_diff * cos(flOffset) - y_diff * sin(flOffset);
  192. float ynew_diff = x_diff * sin(flOffset) + y_diff * cos(flOffset);
  193. // The dot is out of the radar's range.. Scale it back so that it appears on the border
  194. if ( (-1 * y_diff) > fRange )
  195. {
  196. float flScale;
  197. flScale = ( -1 * y_diff) / fRange;
  198. xnew_diff /= flScale;
  199. ynew_diff /= flScale;
  200. }
  201. xnew_diff /= 32;
  202. ynew_diff /= 32;
  203. //output
  204. x = (iRadarRadius/2) + (int)xnew_diff;
  205. y = (iRadarRadius/2) + (int)ynew_diff;
  206. z_delta = location.z - origin.z;
  207. }
  208. void CHudRadar::DrawPlayerOnRadar( int iPlayer, C_CSPlayer *pLocalPlayer )
  209. {
  210. float x, y, z_delta;
  211. int iBaseDotSize = ScreenWidth() / 256;
  212. int r, g, b, a = 235;
  213. C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
  214. if ( !pCSPR )
  215. return;
  216. C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( iPlayer ) );
  217. if ( !pPlayer )
  218. return;
  219. bool bOppositeTeams = (pLocalPlayer->GetTeamNumber() != TEAM_UNASSIGNED && pCSPR->GetTeam( iPlayer ) != pLocalPlayer->GetTeamNumber());
  220. if ( bOppositeTeams && pPlayer->m_bDetected == false )
  221. return;
  222. WorldToRadar( pPlayer->GetAbsOrigin(), pLocalPlayer->GetAbsOrigin(), pLocalPlayer->LocalEyeAngles(), x, y, z_delta );
  223. if( pCSPR->HasC4( iPlayer ) || pCSPR->IsVIP( iPlayer ) || bOppositeTeams )
  224. {
  225. r = 250; g = 0; b = 0;
  226. }
  227. else if ( 0 /*m_bTrackArray[i-1] == true */ ) // Tracked players (friends we want to keep track of on the radar)
  228. {
  229. iBaseDotSize *= 2;
  230. r = 185; g = 20; b = 20;
  231. }
  232. else
  233. {
  234. r = 75; g = 75; b = 250;
  235. }
  236. // Handle the radio flashes
  237. bool bRadarFlash = false;
  238. if ( g_RadarFlashes.Count() > iPlayer )
  239. bRadarFlash = g_RadarFlashes[iPlayer].m_bRadarFlash && g_RadarFlashes[iPlayer].m_iNumRadarFlashes > 0;
  240. if ( bRadarFlash || GetClientVoiceMgr()->IsPlayerSpeaking( iPlayer ) )
  241. {
  242. r = 230; g = 110; b = 25; a = 245;
  243. DrawRadarDot( x, y, z_delta, iBaseDotSize, RADAR_DOT_LARGE_FLASH, r, g, b, a );
  244. }
  245. else
  246. {
  247. DrawRadarDot( x, y, z_delta, iBaseDotSize, RADAR_DOT_NORMAL, r, g, b, a );
  248. }
  249. }
  250. void CHudRadar::DrawEntityOnRadar( CBaseEntity *pEnt, C_CSPlayer *pLocalPlayer, int flags, int r, int g, int b, int a )
  251. {
  252. float x, y, z_delta;
  253. int iBaseDotSize = 4;
  254. WorldToRadar( pEnt->GetAbsOrigin(), pLocalPlayer->GetAbsOrigin(), pLocalPlayer->LocalEyeAngles(), x, y, z_delta );
  255. if( flags & RADAR_IGNORE_Z )
  256. z_delta = 0;
  257. DrawRadarDot( x, y, z_delta, iBaseDotSize, flags, r, g, b, a );
  258. }
  259. void CHudRadar::FillRect( int x, int y, int w, int h )
  260. {
  261. int panel_x, panel_y, panel_w, panel_h;
  262. GetBounds( panel_x, panel_y, panel_w, panel_h );
  263. vgui::surface()->DrawFilledRect( x, y, x+w, y+h );
  264. }
  265. void CHudRadar::DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a )
  266. {
  267. vgui::surface()->DrawSetColor( r, g, b, a );
  268. if ( flags & RADAR_DOT_LARGE_FLASH )
  269. {
  270. FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
  271. }
  272. else if ( z_diff < -128 ) // below the player
  273. {
  274. z_diff *= -1;
  275. if ( z_diff > 3096 )
  276. {
  277. z_diff = 3096;
  278. }
  279. int iBar = (int)( z_diff / 400 ) + 2;
  280. // Draw an upside-down T shape to symbolize the dot is below the player.
  281. iBaseDotSize /= 2;
  282. //horiz
  283. FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
  284. //vert
  285. FillRect( x, y - iBar*iBaseDotSize, iBaseDotSize, iBar*iBaseDotSize );
  286. }
  287. else if ( z_diff > 128 ) // above the player
  288. {
  289. if ( z_diff > 3096 )
  290. {
  291. z_diff = 3096;
  292. }
  293. int iBar = (int)( z_diff / 400 ) + 2;
  294. iBaseDotSize /= 2;
  295. // Draw a T shape to symbolize the dot is above the player.
  296. //horiz
  297. FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
  298. //vert
  299. FillRect( x, y, iBaseDotSize, iBar*iBaseDotSize );
  300. }
  301. else
  302. {
  303. if ( flags & RADAR_DOT_HOSTAGE )
  304. {
  305. FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
  306. }
  307. else if ( flags & RADAR_DOT_BOMB )
  308. {
  309. if ( flags & RADAR_DOT_BOMB_PLANTED )
  310. {
  311. iBaseDotSize = 2;
  312. // draw an X for the planted bomb
  313. FillRect( x, y, iBaseDotSize, iBaseDotSize );
  314. FillRect( x-2, y-2, iBaseDotSize, iBaseDotSize );
  315. FillRect( x-2, y+2, iBaseDotSize, iBaseDotSize );
  316. FillRect( x+2, y-2, iBaseDotSize, iBaseDotSize );
  317. FillRect( x+2, y+2, iBaseDotSize, iBaseDotSize );
  318. }
  319. else
  320. {
  321. FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
  322. }
  323. }
  324. else
  325. {
  326. FillRect( x, y, iBaseDotSize, iBaseDotSize );
  327. }
  328. }
  329. }
  330. void Radar_FlashPlayer( int iPlayer )
  331. {
  332. if ( g_RadarFlashes.Count() <= iPlayer )
  333. {
  334. g_RadarFlashes.AddMultipleToTail( iPlayer - g_RadarFlashes.Count() + 1 );
  335. }
  336. CPlayerRadarFlash *pFlash = &g_RadarFlashes[iPlayer];
  337. pFlash->m_flNextRadarFlashTime = gpGlobals->curtime;
  338. pFlash->m_iNumRadarFlashes = 16;
  339. pFlash->m_bRadarFlash = false;
  340. g_pMapOverview->FlashEntity(iPlayer);
  341. }
  342. CON_COMMAND( drawradar, "Draws HUD radar" )
  343. {
  344. (GET_HUDELEMENT( CHudRadar ))->DrawRadar();
  345. }
  346. CON_COMMAND( hideradar, "Hides HUD radar" )
  347. {
  348. (GET_HUDELEMENT( CHudRadar ))->HideRadar();
  349. }
  350. //////////////////////////////////////////////////////////////////////////
  351. //////////////////////////////////////////////////////////////////////////
  352. //////////////////////////////////////////////////////////////////////////
  353. // Location text under radar
  354. DECLARE_HUDELEMENT( CHudLocation );
  355. CHudLocation::CHudLocation( const char *pName ) : vgui::Label( NULL, "HudLocation", "" ), CHudElement( pName )
  356. {
  357. SetParent( g_pClientMode->GetViewport() );
  358. }
  359. void CHudLocation::Init()
  360. {
  361. // Make sure we get ticked...
  362. vgui::ivgui()->AddTickSignal( GetVPanel() );
  363. }
  364. void CHudLocation::LevelInit()
  365. {
  366. }
  367. bool CHudLocation::ShouldDraw()
  368. {
  369. CCSMapOverview *pCSMapOverview = (CCSMapOverview *)GET_HUDELEMENT( CCSMapOverview );
  370. if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_RADAR && pCSMapOverview && pCSMapOverview->ShouldDraw() == true )
  371. return true;
  372. else if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_INSET )
  373. return true;
  374. return false;
  375. }
  376. void CHudLocation::ApplySchemeSettings(vgui::IScheme *pScheme)
  377. {
  378. BaseClass::ApplySchemeSettings( pScheme );
  379. m_fgColor = Color( 64, 255, 64, 255 );
  380. SetFont( pScheme->GetFont( "ChatFont" ) );
  381. SetBorder( NULL );
  382. SetBgColor( Color( 0, 0, 0, 0 ) );
  383. SetFgColor( m_fgColor );
  384. }
  385. void CHudLocation::OnTick()
  386. {
  387. m_fgColor[3] = cl_locationalpha.GetInt();
  388. SetFgColor( m_fgColor );
  389. const char *pszLocation = "";
  390. C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
  391. if ( pPlayer )
  392. {
  393. pszLocation = pPlayer->GetLastKnownPlaceName();
  394. }
  395. SetText( g_pVGuiLocalize->Find( pszLocation ) );
  396. // We have two different locations based on the Overview mode.
  397. // So we just position ourselves below, and center our text in their width.
  398. if( g_pMapOverview )
  399. {
  400. int x = 0, y = 0;
  401. int width = 0, height = 0;
  402. g_pMapOverview->GetAsPanel()->GetPos( x, y );
  403. g_pMapOverview->GetAsPanel()->GetSize( width, height );
  404. y += g_pMapOverview->GetAsPanel()->GetTall();
  405. SetPos( x, y );
  406. SetWide( width );
  407. }
  408. }