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.

465 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Item pickup history displayed onscreen when items are picked up.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "history_resource.h"
  9. #include "hud_macros.h"
  10. #include <vgui_controls/Controls.h>
  11. #include <vgui/ILocalize.h>
  12. #include <vgui/ISurface.h>
  13. #include "iclientmode.h"
  14. #include "vgui_controls/AnimationController.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. using namespace vgui;
  18. extern ConVar hud_drawhistory_time;
  19. DECLARE_HUDELEMENT( CHudHistoryResource );
  20. DECLARE_HUD_MESSAGE( CHudHistoryResource, ItemPickup );
  21. DECLARE_HUD_MESSAGE( CHudHistoryResource, AmmoDenied );
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Constructor
  24. //-----------------------------------------------------------------------------
  25. CHudHistoryResource::CHudHistoryResource( const char *pElementName ) :
  26. CHudElement( pElementName ), BaseClass( NULL, "HudHistoryResource" )
  27. {
  28. vgui::Panel *pParent = g_pClientMode->GetViewport();
  29. SetParent( pParent );
  30. m_bDoNotDraw = true;
  31. m_wcsAmmoFullMsg[0] = 0;
  32. m_bNeedsDraw = false;
  33. SetHiddenBits( HIDEHUD_MISCSTATUS );
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. void CHudHistoryResource::ApplySchemeSettings( IScheme *pScheme )
  39. {
  40. BaseClass::ApplySchemeSettings( pScheme );
  41. SetPaintBackgroundEnabled( false );
  42. // lookup text to display for ammo full message
  43. wchar_t *wcs = g_pVGuiLocalize->Find("#hl2_AmmoFull");
  44. if (wcs)
  45. {
  46. wcsncpy(m_wcsAmmoFullMsg, wcs, sizeof(m_wcsAmmoFullMsg) / sizeof(wchar_t));
  47. }
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Purpose:
  51. //-----------------------------------------------------------------------------
  52. void CHudHistoryResource::Init( void )
  53. {
  54. HOOK_HUD_MESSAGE( CHudHistoryResource, ItemPickup );
  55. HOOK_HUD_MESSAGE( CHudHistoryResource, AmmoDenied );
  56. Reset();
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose:
  60. //-----------------------------------------------------------------------------
  61. void CHudHistoryResource::Reset( void )
  62. {
  63. m_PickupHistory.RemoveAll();
  64. m_iCurrentHistorySlot = 0;
  65. m_bDoNotDraw = true;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: these kept only for hl1-port compatibility
  69. //-----------------------------------------------------------------------------
  70. void CHudHistoryResource::SetHistoryGap( int iNewHistoryGap )
  71. {
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose: adds an element to the history
  75. //-----------------------------------------------------------------------------
  76. void CHudHistoryResource::AddToHistory( C_BaseCombatWeapon *weapon )
  77. {
  78. // don't draw exhaustable weapons (grenades) since they'll have an ammo pickup icon as well
  79. if ( weapon->GetWpnData().iFlags & ITEM_FLAG_EXHAUSTIBLE )
  80. return;
  81. int iId = weapon->entindex();
  82. // don't show the same weapon twice
  83. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  84. {
  85. if ( m_PickupHistory[i].iId == iId )
  86. {
  87. // it's already in list
  88. return;
  89. }
  90. }
  91. AddIconToHistory( HISTSLOT_WEAP, iId, weapon, 0, NULL );
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose: Add a new entry to the pickup history
  95. //-----------------------------------------------------------------------------
  96. void CHudHistoryResource::AddToHistory( int iType, int iId, int iCount )
  97. {
  98. // Ignore adds with no count
  99. if ( iType == HISTSLOT_AMMO )
  100. {
  101. if ( !iCount )
  102. return;
  103. #if defined( CSTRIKE_DLL )
  104. // don't leave blank gaps for ammo we're not going to display
  105. const FileWeaponInfo_t *pWpnInfo = gWR.GetWeaponFromAmmo( iId );
  106. if ( pWpnInfo && ( pWpnInfo->iMaxClip1 >= 0 || pWpnInfo->iMaxClip2 >= 0 ) )
  107. {
  108. if ( !pWpnInfo->iconSmall )
  109. return;
  110. }
  111. #endif
  112. // clear out any ammo pickup denied icons, since we can obviously pickup again
  113. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  114. {
  115. if ( m_PickupHistory[i].type == HISTSLOT_AMMODENIED && m_PickupHistory[i].iId == iId )
  116. {
  117. // kill the old entry
  118. m_PickupHistory[i].DisplayTime = 0.0f;
  119. // change the pickup to be in this entry
  120. m_iCurrentHistorySlot = i;
  121. break;
  122. }
  123. }
  124. }
  125. AddIconToHistory( iType, iId, NULL, iCount, NULL );
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose: Add a new entry to the pickup history
  129. //-----------------------------------------------------------------------------
  130. void CHudHistoryResource::AddToHistory( int iType, const char *szName, int iCount )
  131. {
  132. if ( iType != HISTSLOT_ITEM )
  133. return;
  134. // Get the item's icon
  135. CHudTexture *i = gHUD.GetIcon( szName );
  136. if ( i == NULL )
  137. return;
  138. AddIconToHistory( iType, 1, NULL, iCount, i );
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: adds a history icon
  142. //-----------------------------------------------------------------------------
  143. void CHudHistoryResource::AddIconToHistory( int iType, int iId, C_BaseCombatWeapon *weapon, int iCount, CHudTexture *icon )
  144. {
  145. m_bNeedsDraw = true;
  146. // Check to see if the pic would have to be drawn too high. If so, start again from the bottom
  147. if ( (m_flHistoryGap * (m_iCurrentHistorySlot+1)) > GetTall() )
  148. {
  149. m_iCurrentHistorySlot = 0;
  150. }
  151. // If the history resource is appearing, slide the hint message element down
  152. if ( m_iCurrentHistorySlot == 0 )
  153. {
  154. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageLower" );
  155. }
  156. // ensure the size
  157. m_PickupHistory.EnsureCount(m_iCurrentHistorySlot + 1);
  158. // default to just writing to the first slot
  159. HIST_ITEM *freeslot = &m_PickupHistory[m_iCurrentHistorySlot];
  160. if ( iType == HISTSLOT_AMMODENIED && freeslot->DisplayTime )
  161. {
  162. // don't override existing pickup icons with denied icons
  163. return;
  164. }
  165. freeslot->iId = iId;
  166. freeslot->icon = icon;
  167. freeslot->type = iType;
  168. freeslot->m_hWeapon = weapon;
  169. freeslot->iCount = iCount;
  170. if (iType == HISTSLOT_AMMODENIED)
  171. {
  172. freeslot->DisplayTime = gpGlobals->curtime + (hud_drawhistory_time.GetFloat() / 2.0f);
  173. }
  174. else
  175. {
  176. freeslot->DisplayTime = gpGlobals->curtime + hud_drawhistory_time.GetFloat();
  177. }
  178. ++m_iCurrentHistorySlot;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose: Handle an item pickup event from the server
  182. //-----------------------------------------------------------------------------
  183. void CHudHistoryResource::MsgFunc_ItemPickup( bf_read &msg )
  184. {
  185. char szName[1024];
  186. msg.ReadString( szName, sizeof(szName) );
  187. // Add the item to the history
  188. AddToHistory( HISTSLOT_ITEM, szName );
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose: ammo denied message
  192. //-----------------------------------------------------------------------------
  193. void CHudHistoryResource::MsgFunc_AmmoDenied( bf_read &msg )
  194. {
  195. int iAmmo = msg.ReadShort();
  196. // see if there are any existing ammo items of that type
  197. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  198. {
  199. if ( m_PickupHistory[i].type == HISTSLOT_AMMO && m_PickupHistory[i].iId == iAmmo )
  200. {
  201. // it's already in the list as a pickup, ignore
  202. return;
  203. }
  204. }
  205. // see if there are any denied ammo icons, if so refresh their timer
  206. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  207. {
  208. if ( m_PickupHistory[i].type == HISTSLOT_AMMODENIED && m_PickupHistory[i].iId == iAmmo )
  209. {
  210. // it's already in the list, refresh
  211. m_PickupHistory[i].DisplayTime = gpGlobals->curtime + (hud_drawhistory_time.GetFloat() / 2.0f);
  212. m_bNeedsDraw = true;
  213. return;
  214. }
  215. }
  216. // add into the list
  217. AddToHistory( HISTSLOT_AMMODENIED, iAmmo, 0 );
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose: If there aren't any items in the history, clear it out.
  221. //-----------------------------------------------------------------------------
  222. void CHudHistoryResource::CheckClearHistory( void )
  223. {
  224. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  225. {
  226. if ( m_PickupHistory[i].type )
  227. return;
  228. }
  229. m_iCurrentHistorySlot = 0;
  230. // Slide the hint message element back up
  231. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageRaise" );
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: Save CPU cycles by letting the HUD system early cull
  235. // costly traversal. Called per frame, return true if thinking and
  236. // painting need to occur.
  237. //-----------------------------------------------------------------------------
  238. bool CHudHistoryResource::ShouldDraw( void )
  239. {
  240. #ifdef TF_CLIENT_DLL
  241. return false;
  242. #else
  243. return ( ( m_iCurrentHistorySlot > 0 || m_bNeedsDraw ) && CHudElement::ShouldDraw() );
  244. #endif
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: Draw the pickup history
  248. //-----------------------------------------------------------------------------
  249. void CHudHistoryResource::Paint( void )
  250. {
  251. if ( m_bDoNotDraw )
  252. {
  253. // this is to not draw things until the first rendered
  254. m_bDoNotDraw = false;
  255. return;
  256. }
  257. // set when drawing should occur
  258. // will be set if valid drawing does occur
  259. m_bNeedsDraw = false;
  260. int wide, tall;
  261. GetSize( wide, tall );
  262. for ( int i = 0; i < m_PickupHistory.Count(); i++ )
  263. {
  264. if ( m_PickupHistory[i].type )
  265. {
  266. m_PickupHistory[i].DisplayTime = MIN( m_PickupHistory[i].DisplayTime, gpGlobals->curtime + hud_drawhistory_time.GetFloat() );
  267. if ( m_PickupHistory[i].DisplayTime <= gpGlobals->curtime )
  268. {
  269. // pic drawing time has expired
  270. memset( &m_PickupHistory[i], 0, sizeof(HIST_ITEM) );
  271. CheckClearHistory();
  272. continue;
  273. }
  274. float elapsed = m_PickupHistory[i].DisplayTime - gpGlobals->curtime;
  275. float scale = elapsed * 80;
  276. Color clr = gHUD.m_clrNormal;
  277. clr[3] = MIN( scale, 255 );
  278. bool bUseAmmoFullMsg = false;
  279. // get the icon and number to draw
  280. const CHudTexture *itemIcon = NULL;
  281. const CHudTexture *itemAmmoIcon = NULL;
  282. int iAmount = 0;
  283. bool bHalfHeight = true;
  284. switch ( m_PickupHistory[i].type )
  285. {
  286. case HISTSLOT_AMMO:
  287. {
  288. // Get the weapon we belong to
  289. #ifndef HL2MP
  290. const FileWeaponInfo_t *pWpnInfo = gWR.GetWeaponFromAmmo( m_PickupHistory[i].iId );
  291. if ( pWpnInfo && ( pWpnInfo->iMaxClip1 >= 0 || pWpnInfo->iMaxClip2 >= 0 ) )
  292. {
  293. // The weapon will be the main icon, and the ammo the smaller
  294. itemIcon = pWpnInfo->iconSmall;
  295. itemAmmoIcon = gWR.GetAmmoIconFromWeapon( m_PickupHistory[i].iId );
  296. }
  297. else
  298. #endif // HL2MP
  299. {
  300. itemIcon = gWR.GetAmmoIconFromWeapon( m_PickupHistory[i].iId );
  301. itemAmmoIcon = NULL;
  302. }
  303. #ifdef CSTRIKE_DLL
  304. // show grenades as the weapon icon
  305. if ( pWpnInfo && pWpnInfo->iFlags & ITEM_FLAG_EXHAUSTIBLE )
  306. {
  307. itemIcon = pWpnInfo->iconActive;
  308. itemAmmoIcon = NULL;
  309. bHalfHeight = false;
  310. }
  311. #endif
  312. iAmount = m_PickupHistory[i].iCount;
  313. }
  314. break;
  315. case HISTSLOT_AMMODENIED:
  316. {
  317. itemIcon = gWR.GetAmmoIconFromWeapon( m_PickupHistory[i].iId );
  318. iAmount = 0;
  319. bUseAmmoFullMsg = true;
  320. // display as red
  321. clr = gHUD.m_clrCaution;
  322. clr[3] = MIN( scale, 255 );
  323. }
  324. break;
  325. case HISTSLOT_WEAP:
  326. {
  327. C_BaseCombatWeapon *pWeapon = m_PickupHistory[i].m_hWeapon;
  328. if ( !pWeapon )
  329. return;
  330. if ( !pWeapon->HasAmmo() )
  331. {
  332. // if the weapon doesn't have ammo, display it as red
  333. clr = gHUD.m_clrCaution;
  334. clr[3] = MIN( scale, 255 );
  335. }
  336. itemIcon = pWeapon->GetSpriteInactive();
  337. bHalfHeight = false;
  338. }
  339. break;
  340. case HISTSLOT_ITEM:
  341. {
  342. if ( !m_PickupHistory[i].iId )
  343. continue;
  344. itemIcon = m_PickupHistory[i].icon;
  345. bHalfHeight = false;
  346. }
  347. break;
  348. default:
  349. // unknown history type
  350. Assert( 0 );
  351. break;
  352. }
  353. if ( !itemIcon )
  354. continue;
  355. if ( clr[3] )
  356. {
  357. // valid drawing will occur
  358. m_bNeedsDraw = true;
  359. }
  360. int ypos = tall - (m_flHistoryGap * (i + 1));
  361. int xpos = wide - itemIcon->Width() - m_flIconInset;
  362. #ifndef HL2MP
  363. // Adjust for a half-height icon
  364. if ( bHalfHeight )
  365. {
  366. ypos += itemIcon->Height() / 2;
  367. }
  368. #endif // HL2MP
  369. itemIcon->DrawSelf( xpos, ypos, clr );
  370. if ( itemAmmoIcon )
  371. {
  372. itemAmmoIcon->DrawSelf( xpos - ( itemAmmoIcon->Width() * 1.25f ), ypos, clr );
  373. }
  374. if ( iAmount )
  375. {
  376. wchar_t text[16];
  377. _snwprintf( text, sizeof( text ) / sizeof(wchar_t), L"%i", m_PickupHistory[i].iCount );
  378. // offset the number to sit properly next to the icon
  379. ypos -= ( surface()->GetFontTall( m_hNumberFont ) - itemIcon->Height() ) / 2;
  380. vgui::surface()->DrawSetTextFont( m_hNumberFont );
  381. vgui::surface()->DrawSetTextColor( clr );
  382. vgui::surface()->DrawSetTextPos( wide - m_flTextInset, ypos );
  383. vgui::surface()->DrawUnicodeString( text );
  384. }
  385. else if ( bUseAmmoFullMsg )
  386. {
  387. // offset the number to sit properly next to the icon
  388. ypos -= ( surface()->GetFontTall( m_hTextFont ) - itemIcon->Height() ) / 2;
  389. vgui::surface()->DrawSetTextFont( m_hTextFont );
  390. vgui::surface()->DrawSetTextColor( clr );
  391. vgui::surface()->DrawSetTextPos( wide - m_flTextInset, ypos );
  392. vgui::surface()->DrawUnicodeString( m_wcsAmmoFullMsg );
  393. }
  394. }
  395. }
  396. }