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.

587 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include <vgui/ISurface.h>
  8. #include "hud_numericdisplay.h"
  9. #include "iclientmode.h"
  10. #include <coordsize.h>
  11. #include "hud_macros.h"
  12. #include "vgui/IVGui.h"
  13. #include "vgui/ILocalize.h"
  14. #include "mapoverview.h"
  15. #include "hud_radar.h"
  16. #include "iclientvehicle.h"
  17. #define RADAR_DOT_NORMAL 0
  18. #define RADAR_IGNORE_Z (1<<6) //always draw this item as if it was at the same Z as the player
  19. #define RADAR_MAX_GHOST_ALPHA 25
  20. DECLARE_VGUI_SCREEN_FACTORY( CHudRadar, "jalopy_radar_panel" );
  21. #define RADAR_PANEL_MATERIAL "vgui/screens/radar"
  22. #define RADAR_CONTACT_LAMBDA_MATERIAL "vgui/icons/icon_lambda" // Lambda cache
  23. #define RADAR_CONTACT_BUSTER_MATERIAL "vgui/icons/icon_buster" // Striderbuster
  24. #define RADAR_CONTACT_STRIDER_MATERIAL "vgui/icons/icon_strider" // Strider
  25. #define RADAR_CONTACT_DOG_MATERIAL "vgui/icons/icon_dog" // Dog
  26. #define RADAR_CONTACT_BASE_MATERIAL "vgui/icons/icon_base" // Ally base
  27. static CHudRadar *s_Radar = NULL;
  28. CHudRadar *GetHudRadar()
  29. {
  30. return s_Radar;
  31. }
  32. DECLARE_HUDELEMENT( CMapOverview );
  33. //---------------------------------------------------------
  34. //---------------------------------------------------------
  35. CHudRadar::CHudRadar( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
  36. {
  37. m_pVehicle = NULL;
  38. m_iImageID = -1;
  39. m_textureID_IconLambda = -1;
  40. m_textureID_IconBuster = -1;
  41. m_textureID_IconStrider = -1;
  42. m_textureID_IconDog = -1;
  43. m_textureID_IconBase = -1;
  44. }
  45. //---------------------------------------------------------
  46. //---------------------------------------------------------
  47. CHudRadar::~CHudRadar()
  48. {
  49. s_Radar = NULL;
  50. #if defined(_X360)
  51. if( m_iImageID != -1 )
  52. {
  53. vgui::surface()->DestroyTextureID( m_iImageID );
  54. m_iImageID = -1;
  55. }
  56. if( m_textureID_IconLambda != -1 )
  57. {
  58. vgui::surface()->DestroyTextureID( m_textureID_IconLambda );
  59. m_textureID_IconLambda = -1;
  60. }
  61. if( m_textureID_IconBuster != -1 )
  62. {
  63. vgui::surface()->DestroyTextureID( m_textureID_IconBuster );
  64. m_textureID_IconBuster = -1;
  65. }
  66. if( m_textureID_IconStrider != -1 )
  67. {
  68. vgui::surface()->DestroyTextureID( m_textureID_IconStrider );
  69. m_textureID_IconStrider = -1;
  70. }
  71. if( m_textureID_IconDog != -1 )
  72. {
  73. vgui::surface()->DestroyTextureID( m_textureID_IconDog );
  74. m_textureID_IconDog = -1;
  75. }
  76. if( m_textureID_IconBase != -1 )
  77. {
  78. vgui::surface()->DestroyTextureID( m_textureID_IconBase );
  79. m_textureID_IconBase = -1;
  80. }
  81. #endif//_X360
  82. }
  83. //---------------------------------------------------------
  84. //---------------------------------------------------------
  85. bool CHudRadar::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
  86. {
  87. bool result = BaseClass::Init( pKeyValues, pInitData );
  88. ClearAllRadarContacts();
  89. s_Radar = this;
  90. m_ghostAlpha = 0;
  91. m_flTimeStartGhosting = gpGlobals->curtime + 1.0f;
  92. return result;
  93. }
  94. //---------------------------------------------------------
  95. //---------------------------------------------------------
  96. void CHudRadar::VidInit(void)
  97. {
  98. }
  99. //---------------------------------------------------------
  100. //---------------------------------------------------------
  101. void CHudRadar::MsgFunc_UpdateRadar(bf_read &msg )
  102. {
  103. }
  104. //---------------------------------------------------------
  105. // Purpose: Register a radar contact in the list of contacts
  106. //---------------------------------------------------------
  107. void CHudRadar::AddRadarContact( const Vector &vecOrigin, int iType, float flTimeToLive )
  108. {
  109. if( m_iNumRadarContacts == RADAR_MAX_CONTACTS )
  110. return;
  111. Vector v = vecOrigin;
  112. int iExistingContact = FindRadarContact( vecOrigin );
  113. if( iExistingContact > -1 )
  114. {
  115. // Just update this contact.
  116. m_radarContacts[iExistingContact].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive;
  117. return;
  118. }
  119. m_radarContacts[m_iNumRadarContacts].m_vecOrigin = vecOrigin;
  120. m_radarContacts[m_iNumRadarContacts].m_iType = iType;
  121. m_radarContacts[m_iNumRadarContacts].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive;
  122. m_iNumRadarContacts++;
  123. }
  124. //---------------------------------------------------------
  125. // Purpose: Search the contact list for a specific contact
  126. //---------------------------------------------------------
  127. int CHudRadar::FindRadarContact( const Vector &vecOrigin )
  128. {
  129. for( int i = 0 ; i < m_iNumRadarContacts ; i++ )
  130. {
  131. if( m_radarContacts[ i ].m_vecOrigin == vecOrigin )
  132. return i;
  133. }
  134. return -1;
  135. }
  136. //---------------------------------------------------------
  137. // Purpose: Go through all radar targets and see if any
  138. // have expired. If yes, remove them from the
  139. // list.
  140. //---------------------------------------------------------
  141. void CHudRadar::MaintainRadarContacts()
  142. {
  143. bool bKeepWorking = true;
  144. while( bKeepWorking )
  145. {
  146. bKeepWorking = false;
  147. for( int i = 0 ; i < m_iNumRadarContacts ; i++ )
  148. {
  149. CRadarContact *pContact = &m_radarContacts[ i ];
  150. if( gpGlobals->curtime >= pContact->m_flTimeToRemove )
  151. {
  152. // Time for this guy to go. Easiest thing is just to copy the last element
  153. // into this element's spot and then decrement the count of entities.
  154. bKeepWorking = true;
  155. m_radarContacts[ i ] = m_radarContacts[ m_iNumRadarContacts - 1 ];
  156. m_iNumRadarContacts--;
  157. break;
  158. }
  159. }
  160. }
  161. }
  162. //---------------------------------------------------------
  163. //---------------------------------------------------------
  164. void CHudRadar::SetVisible(bool state)
  165. {
  166. BaseClass::SetVisible(state);
  167. if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_RADAR )
  168. {
  169. // We are the hud element still, but he is in charge of the new style now.
  170. g_pMapOverview->SetVisible( state );
  171. }
  172. }
  173. #define RADAR_BLIP_FADE_TIME 1.0f
  174. #define RADAR_USE_ICONS 1
  175. //---------------------------------------------------------
  176. // Purpose: Draw the radar panel.
  177. // We're probably doing too much other work in here
  178. //---------------------------------------------------------
  179. void CHudRadar::Paint()
  180. {
  181. if (m_iImageID == -1 )
  182. {
  183. // Set up the image ID's if they've somehow gone bad.
  184. m_textureID_IconLambda = vgui::surface()->CreateNewTextureID();
  185. vgui::surface()->DrawSetTextureFile( m_textureID_IconLambda, RADAR_CONTACT_LAMBDA_MATERIAL, true, false );
  186. m_textureID_IconBuster = vgui::surface()->CreateNewTextureID();
  187. vgui::surface()->DrawSetTextureFile( m_textureID_IconBuster, RADAR_CONTACT_BUSTER_MATERIAL, true, false );
  188. m_textureID_IconStrider = vgui::surface()->CreateNewTextureID();
  189. vgui::surface()->DrawSetTextureFile( m_textureID_IconStrider, RADAR_CONTACT_STRIDER_MATERIAL, true, false );
  190. m_textureID_IconDog = vgui::surface()->CreateNewTextureID();
  191. vgui::surface()->DrawSetTextureFile( m_textureID_IconDog, RADAR_CONTACT_DOG_MATERIAL, true, false );
  192. m_textureID_IconBase = vgui::surface()->CreateNewTextureID();
  193. vgui::surface()->DrawSetTextureFile( m_textureID_IconBase, RADAR_CONTACT_BASE_MATERIAL, true, false );
  194. m_iImageID = vgui::surface()->CreateNewTextureID();
  195. vgui::surface()->DrawSetTextureFile( m_iImageID, RADAR_PANEL_MATERIAL, true, false );
  196. }
  197. // Draw the radar background.
  198. int wide, tall;
  199. GetSize(wide, tall);
  200. int alpha = 255;
  201. vgui::surface()->DrawSetColor(255, 255, 255, alpha);
  202. vgui::surface()->DrawSetTexture(m_iImageID);
  203. vgui::surface()->DrawTexturedRect(0, 0, wide, tall);
  204. // Manage the CRT 'ghosting' effect
  205. if( gpGlobals->curtime > m_flTimeStartGhosting )
  206. {
  207. if( m_ghostAlpha < RADAR_MAX_GHOST_ALPHA )
  208. {
  209. m_ghostAlpha++;
  210. }
  211. else
  212. {
  213. m_flTimeStartGhosting = FLT_MAX;
  214. m_flTimeStopGhosting = gpGlobals->curtime + RandomFloat( 1.0f, 2.0f );// How long to ghost for
  215. }
  216. }
  217. else if( gpGlobals->curtime > m_flTimeStopGhosting )
  218. {
  219. // We're supposed to stop ghosting now.
  220. if( m_ghostAlpha > 0 )
  221. {
  222. // Still fading the effects.
  223. m_ghostAlpha--;
  224. }
  225. else
  226. {
  227. // DONE fading the effects. Now stop ghosting for a short while
  228. m_flTimeStartGhosting = gpGlobals->curtime + RandomFloat( 2.0f, 3.0f );// how long between ghosts
  229. m_flTimeStopGhosting = FLT_MAX;
  230. }
  231. }
  232. // Now go through the list of radar targets and represent them on the radar screen
  233. // by drawing their icons on top of the background.
  234. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  235. for( int i = 0 ; i < m_iNumRadarContacts ; i++ )
  236. {
  237. int alpha = 90;
  238. CRadarContact *pContact = &m_radarContacts[ i ];
  239. float deltaT = pContact->m_flTimeToRemove - gpGlobals->curtime;
  240. if ( deltaT < RADAR_BLIP_FADE_TIME )
  241. {
  242. float factor = deltaT / RADAR_BLIP_FADE_TIME;
  243. alpha = (int) ( ((float)alpha) * factor );
  244. if( alpha < 10 )
  245. alpha = 10;
  246. }
  247. if( RADAR_USE_ICONS )
  248. {
  249. int flicker = RandomInt( 0, 30 );
  250. DrawIconOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha + flicker );
  251. }
  252. else
  253. {
  254. DrawPositionOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha );
  255. }
  256. }
  257. MaintainRadarContacts();
  258. }
  259. ConVar radar_range("radar_range", "3000" ); // 180 feet
  260. //---------------------------------------------------------
  261. // Scale maps the distance of the target from the radar
  262. // source.
  263. //
  264. // 1.0 = target at or beyond radar range.
  265. // 0.5 = target at (radar_range * 0.5) units distance
  266. // 0.25 = target at (radar_range * 0.25) units distance
  267. // -etc-
  268. //---------------------------------------------------------
  269. bool CHudRadar::WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta, float &scale )
  270. {
  271. bool bInRange = true;
  272. float x_diff = location.x - origin.x;
  273. float y_diff = location.y - origin.y;
  274. // Supply epsilon values to avoid divide-by-zero
  275. if(x_diff == 0)
  276. x_diff = 0.00001f;
  277. if(y_diff == 0)
  278. y_diff = 0.00001f;
  279. int iRadarRadius = GetWide(); //width of the panel
  280. float fRange = radar_range.GetFloat();
  281. // This magic /2.15 makes the radar scale seem smaller than the VGUI panel so the icons clamp
  282. // to the outer ring in the radar graphic, not the very edge of the panel itself.
  283. float fScale = (iRadarRadius/2.15f) / fRange;
  284. float flOffset = atan(y_diff/x_diff);
  285. flOffset *= 180;
  286. flOffset /= M_PI;
  287. if ((x_diff < 0) && (y_diff >= 0))
  288. flOffset = 180 + flOffset;
  289. else if ((x_diff < 0) && (y_diff < 0))
  290. flOffset = 180 + flOffset;
  291. else if ((x_diff >= 0) && (y_diff < 0))
  292. flOffset = 360 + flOffset;
  293. y_diff = -1*(sqrt((x_diff)*(x_diff) + (y_diff)*(y_diff)));
  294. x_diff = 0;
  295. flOffset = angles.y - flOffset;
  296. flOffset *= M_PI;
  297. flOffset /= 180; // now theta is in radians
  298. // Transform relative to radar source
  299. float xnew_diff = x_diff * cos(flOffset) - y_diff * sin(flOffset);
  300. float ynew_diff = x_diff * sin(flOffset) + y_diff * cos(flOffset);
  301. if ( (-1 * y_diff) > fRange )
  302. {
  303. float flScale;
  304. flScale = ( -1 * y_diff) / fRange;
  305. xnew_diff /= (flScale);
  306. ynew_diff /= (flScale);
  307. bInRange = false;
  308. scale = 1.0f;
  309. }
  310. else
  311. {
  312. // scale
  313. float flDist = sqrt( ((xnew_diff)*(xnew_diff) + (ynew_diff)*(ynew_diff)) );
  314. scale = flDist / fRange;
  315. }
  316. // Scale the dot's position to match radar scale
  317. xnew_diff *= fScale;
  318. ynew_diff *= fScale;
  319. // Translate to screen coordinates
  320. x = (iRadarRadius/2) + (int)xnew_diff;
  321. y = (iRadarRadius/2) + (int)ynew_diff;
  322. z_delta = 0.0f;
  323. return bInRange;
  324. }
  325. void CHudRadar::DrawPositionOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a )
  326. {
  327. float x, y, z_delta;
  328. int iBaseDotSize = 3;
  329. QAngle viewAngle = pLocalPlayer->EyeAngles();
  330. if( m_pVehicle != NULL )
  331. {
  332. viewAngle = m_pVehicle->GetAbsAngles();
  333. viewAngle.y += 90.0f;
  334. }
  335. float flScale;
  336. WorldToRadar( vecPos, pLocalPlayer->GetAbsOrigin(), viewAngle, x, y, z_delta, flScale );
  337. if( flags & RADAR_IGNORE_Z )
  338. z_delta = 0;
  339. switch( type )
  340. {
  341. case RADAR_CONTACT_GENERIC:
  342. r = 255; g = 170; b = 0;
  343. iBaseDotSize *= 2;
  344. break;
  345. case RADAR_CONTACT_MAGNUSSEN_RDU:
  346. r = 0; g = 200; b = 255;
  347. iBaseDotSize *= 2;
  348. break;
  349. case RADAR_CONTACT_ENEMY:
  350. r = 255; g = 0; b = 0;
  351. iBaseDotSize *= 2;
  352. break;
  353. case RADAR_CONTACT_LARGE_ENEMY:
  354. r = 255; g = 0; b = 0;
  355. iBaseDotSize *= 3;
  356. break;
  357. }
  358. DrawRadarDot( x, y, z_delta, iBaseDotSize, flags, r, g, b, a );
  359. }
  360. //---------------------------------------------------------
  361. // Purpose: Compute the proper position on the radar screen
  362. // for this object's position relative to the player.
  363. // Then draw the icon in the proper location on the
  364. // radar screen.
  365. //---------------------------------------------------------
  366. #define RADAR_ICON_MIN_SCALE 0.75f
  367. #define RADAR_ICON_MAX_SCALE 1.0f
  368. void CHudRadar::DrawIconOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a )
  369. {
  370. float x, y, z_delta;
  371. int wide, tall;
  372. // for 'ghosting' CRT effects:
  373. int xmod;
  374. int ymod;
  375. int xoffset;
  376. int yoffset;
  377. // Assume we're going to use the player's location and orientation
  378. QAngle viewAngle = pLocalPlayer->EyeAngles();
  379. Vector viewOrigin = pLocalPlayer->GetAbsOrigin();
  380. // However, happily use those of the vehicle if available!
  381. if( m_pVehicle != NULL )
  382. {
  383. viewAngle = m_pVehicle->GetAbsAngles();
  384. viewAngle.y += 90.0f;
  385. viewOrigin = m_pVehicle->WorldSpaceCenter();
  386. }
  387. float flScale;
  388. WorldToRadar( vecPos, viewOrigin, viewAngle, x, y, z_delta, flScale );
  389. flScale = RemapVal( flScale, 1.0f, 0.0f, RADAR_ICON_MIN_SCALE, RADAR_ICON_MAX_SCALE );
  390. // Get the correct icon for this type of contact
  391. int iTextureID_Icon = -1;
  392. switch( type )
  393. {
  394. case RADAR_CONTACT_GENERIC:
  395. iTextureID_Icon = m_textureID_IconLambda;
  396. break;
  397. case RADAR_CONTACT_MAGNUSSEN_RDU:
  398. iTextureID_Icon = m_textureID_IconBuster;
  399. break;
  400. case RADAR_CONTACT_LARGE_ENEMY:
  401. case RADAR_CONTACT_ENEMY:
  402. iTextureID_Icon = m_textureID_IconStrider;
  403. break;
  404. case RADAR_CONTACT_DOG:
  405. iTextureID_Icon = m_textureID_IconDog;
  406. break;
  407. case RADAR_CONTACT_ALLY_INSTALLATION:
  408. iTextureID_Icon = m_textureID_IconBase;
  409. break;
  410. default:
  411. return;
  412. break;
  413. }
  414. vgui::surface()->DrawSetColor( r, g, b, a );
  415. vgui::surface()->DrawSetTexture( iTextureID_Icon );
  416. vgui::surface()->DrawGetTextureSize( iTextureID_Icon, wide, tall );
  417. wide = ( int((float)wide * flScale) );
  418. tall = ( int((float)tall * flScale) );
  419. if( type == RADAR_CONTACT_LARGE_ENEMY )
  420. {
  421. wide *= 2;
  422. tall *= 2;
  423. }
  424. // Center the icon around its position.
  425. x -= (wide >> 1);
  426. y -= (tall >> 1);
  427. vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall);
  428. // Draw the crt 'ghost' if the icon is not pegged to the outer rim
  429. if( flScale > RADAR_ICON_MIN_SCALE && m_ghostAlpha > 0 )
  430. {
  431. vgui::surface()->DrawSetColor( r, g, b, m_ghostAlpha );
  432. xmod = RandomInt( 1, 4 );
  433. ymod = RandomInt( 1, 4 );
  434. xoffset = RandomInt( -1, 1 );
  435. yoffset = RandomInt( -1, 1 );
  436. x -= (xmod - xoffset);
  437. y -= (ymod - yoffset);
  438. wide += (xmod + xoffset);
  439. tall += (ymod + yoffset);
  440. vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall);
  441. }
  442. }
  443. void CHudRadar::FillRect( int x, int y, int w, int h )
  444. {
  445. int panel_x, panel_y, panel_w, panel_h;
  446. GetBounds( panel_x, panel_y, panel_w, panel_h );
  447. vgui::surface()->DrawFilledRect( x, y, x+w, y+h );
  448. }
  449. void CHudRadar::DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a )
  450. {
  451. vgui::surface()->DrawSetColor( r, g, b, a );
  452. if ( z_diff < -128 ) // below the player
  453. {
  454. z_diff *= -1;
  455. if ( z_diff > 3096 )
  456. {
  457. z_diff = 3096;
  458. }
  459. int iBar = (int)( z_diff / 400 ) + 2;
  460. // Draw an upside-down T shape to symbolize the dot is below the player.
  461. iBaseDotSize /= 2;
  462. //horiz
  463. FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
  464. //vert
  465. FillRect( x, y - iBar*iBaseDotSize, iBaseDotSize, iBar*iBaseDotSize );
  466. }
  467. else if ( z_diff > 128 ) // above the player
  468. {
  469. if ( z_diff > 3096 )
  470. {
  471. z_diff = 3096;
  472. }
  473. int iBar = (int)( z_diff / 400 ) + 2;
  474. iBaseDotSize /= 2;
  475. // Draw a T shape to symbolize the dot is above the player.
  476. //horiz
  477. FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
  478. //vert
  479. FillRect( x, y, iBaseDotSize, iBar*iBaseDotSize );
  480. }
  481. else
  482. {
  483. FillRect( x, y, iBaseDotSize, iBaseDotSize );
  484. }
  485. }