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.

419 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This is an entity that represents a vgui screen
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "vguiscreen.h"
  9. #include "networkstringtable_gamedll.h"
  10. #include "saverestore_stringtable.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. //-----------------------------------------------------------------------------
  14. // This is an entity that represents a vgui screen
  15. //-----------------------------------------------------------------------------
  16. IMPLEMENT_SERVERCLASS_ST(CVGuiScreen, DT_VGuiScreen)
  17. SendPropFloat(SENDINFO(m_flWidth), 0, SPROP_NOSCALE ),
  18. SendPropFloat(SENDINFO(m_flHeight), 0, SPROP_NOSCALE ),
  19. SendPropInt(SENDINFO(m_nAttachmentIndex), 5, SPROP_UNSIGNED ),
  20. SendPropInt(SENDINFO(m_nPanelName), MAX_VGUI_SCREEN_STRING_BITS, SPROP_UNSIGNED ),
  21. SendPropInt(SENDINFO(m_fScreenFlags), VGUI_SCREEN_MAX_BITS, SPROP_UNSIGNED ),
  22. SendPropInt(SENDINFO(m_nOverlayMaterial), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ),
  23. SendPropEHandle(SENDINFO(m_hPlayerOwner)),
  24. END_SEND_TABLE();
  25. LINK_ENTITY_TO_CLASS( vgui_screen, CVGuiScreen );
  26. LINK_ENTITY_TO_CLASS( vgui_screen_team, CVGuiScreen );
  27. PRECACHE_REGISTER( vgui_screen );
  28. //-----------------------------------------------------------------------------
  29. // Save/load
  30. //-----------------------------------------------------------------------------
  31. BEGIN_DATADESC( CVGuiScreen )
  32. DEFINE_CUSTOM_FIELD( m_nPanelName, &g_VguiScreenStringOps ),
  33. DEFINE_FIELD( m_nAttachmentIndex, FIELD_INTEGER ),
  34. // DEFINE_FIELD( m_nOverlayMaterial, FIELD_INTEGER ),
  35. DEFINE_FIELD( m_fScreenFlags, FIELD_INTEGER ),
  36. DEFINE_KEYFIELD( m_flWidth, FIELD_FLOAT, "width" ),
  37. DEFINE_KEYFIELD( m_flHeight, FIELD_FLOAT, "height" ),
  38. DEFINE_KEYFIELD( m_strOverlayMaterial, FIELD_STRING, "overlaymaterial" ),
  39. DEFINE_FIELD( m_hPlayerOwner, FIELD_EHANDLE ),
  40. DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ),
  41. DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ),
  42. END_DATADESC()
  43. //-----------------------------------------------------------------------------
  44. // Constructor
  45. //-----------------------------------------------------------------------------
  46. CVGuiScreen::CVGuiScreen()
  47. {
  48. m_nOverlayMaterial = OVERLAY_MATERIAL_INVALID_STRING;
  49. m_hPlayerOwner = NULL;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Read in worldcraft data...
  53. //-----------------------------------------------------------------------------
  54. bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue )
  55. {
  56. //!! temp hack, until worldcraft is fixed
  57. // strip the # tokens from (duplicate) key names
  58. char *s = (char *)strchr( szKeyName, '#' );
  59. if ( s )
  60. {
  61. *s = '\0';
  62. }
  63. if ( FStrEq( szKeyName, "panelname" ))
  64. {
  65. SetPanelName( szValue );
  66. return true;
  67. }
  68. // NOTE: Have to do these separate because they set two values instead of one
  69. if( FStrEq( szKeyName, "angles" ) )
  70. {
  71. Assert( GetMoveParent() == NULL );
  72. QAngle angles;
  73. UTIL_StringToVector( angles.Base(), szValue );
  74. // Because the vgui screen basis is strange (z is front, y is up, x is right)
  75. // we need to rotate the typical basis before applying it
  76. VMatrix mat, rotation, tmp;
  77. MatrixFromAngles( angles, mat );
  78. MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 );
  79. MatrixMultiply( mat, rotation, tmp );
  80. MatrixBuildRotateZ( rotation, 90 );
  81. MatrixMultiply( tmp, rotation, mat );
  82. MatrixToAngles( mat, angles );
  83. SetAbsAngles( angles );
  84. return true;
  85. }
  86. return BaseClass::KeyValue( szKeyName, szValue );
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Precache...
  90. //-----------------------------------------------------------------------------
  91. void CVGuiScreen::Precache()
  92. {
  93. BaseClass::Precache();
  94. if ( m_strOverlayMaterial != NULL_STRING )
  95. {
  96. PrecacheMaterial( STRING(m_strOverlayMaterial) );
  97. }
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Spawn...
  101. //-----------------------------------------------------------------------------
  102. void CVGuiScreen::Spawn()
  103. {
  104. Precache();
  105. // This has no model, but we want it to transmit if it's in the PVS anyways
  106. AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  107. m_nAttachmentIndex = 0;
  108. SetSolid( SOLID_OBB );
  109. AddSolidFlags( FSOLID_NOT_SOLID );
  110. SetActualSize( m_flWidth, m_flHeight );
  111. m_fScreenFlags.Set( VGUI_SCREEN_ACTIVE );
  112. m_takedamage = DAMAGE_NO;
  113. AddFlag( FL_NOTARGET );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Spawn...
  117. //-----------------------------------------------------------------------------
  118. void CVGuiScreen::Activate()
  119. {
  120. BaseClass::Activate();
  121. if ( m_nOverlayMaterial == OVERLAY_MATERIAL_INVALID_STRING && m_strOverlayMaterial != NULL_STRING )
  122. {
  123. SetOverlayMaterial( STRING(m_strOverlayMaterial) );
  124. }
  125. }
  126. void CVGuiScreen::OnRestore()
  127. {
  128. UpdateTransmitState();
  129. BaseClass::OnRestore();
  130. }
  131. void CVGuiScreen::SetAttachmentIndex( int nIndex )
  132. {
  133. m_nAttachmentIndex = nIndex;
  134. }
  135. void CVGuiScreen::SetOverlayMaterial( const char *pMaterial )
  136. {
  137. int iMaterial = GetMaterialIndex( pMaterial );
  138. if ( iMaterial == 0 )
  139. {
  140. m_nOverlayMaterial = OVERLAY_MATERIAL_INVALID_STRING;
  141. }
  142. else
  143. {
  144. m_nOverlayMaterial = iMaterial;
  145. }
  146. }
  147. bool CVGuiScreen::IsActive() const
  148. {
  149. return (m_fScreenFlags & VGUI_SCREEN_ACTIVE) != 0;
  150. }
  151. void CVGuiScreen::SetActive( bool bActive )
  152. {
  153. if (bActive != IsActive())
  154. {
  155. if (!bActive)
  156. {
  157. m_fScreenFlags &= ~VGUI_SCREEN_ACTIVE;
  158. }
  159. else
  160. {
  161. m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_ACTIVE );
  162. }
  163. }
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. // Output : Returns true on success, false on failure.
  168. //-----------------------------------------------------------------------------
  169. bool CVGuiScreen::IsAttachedToViewModel() const
  170. {
  171. return (m_fScreenFlags & VGUI_SCREEN_ATTACHED_TO_VIEWMODEL) != 0;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose:
  175. // Input : bAttached -
  176. //-----------------------------------------------------------------------------
  177. void CVGuiScreen::SetAttachedToViewModel( bool bAttached )
  178. {
  179. if (bAttached != IsActive())
  180. {
  181. if (!bAttached)
  182. {
  183. m_fScreenFlags &= ~VGUI_SCREEN_ATTACHED_TO_VIEWMODEL;
  184. }
  185. else
  186. {
  187. m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_ATTACHED_TO_VIEWMODEL );
  188. // attached screens have different transmit rules
  189. DispatchUpdateTransmitState();
  190. }
  191. // attached screens have different transmit rules
  192. DispatchUpdateTransmitState();
  193. }
  194. }
  195. void CVGuiScreen::SetTransparency( bool bTransparent )
  196. {
  197. if (!bTransparent)
  198. {
  199. m_fScreenFlags &= ~VGUI_SCREEN_TRANSPARENT;
  200. }
  201. else
  202. {
  203. m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_TRANSPARENT );
  204. }
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. void CVGuiScreen::InputSetActive( inputdata_t &inputdata )
  210. {
  211. SetActive( true );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. void CVGuiScreen::InputSetInactive( inputdata_t &inputdata )
  217. {
  218. SetActive( false );
  219. }
  220. bool CVGuiScreen::IsVisibleOnlyToTeammates() const
  221. {
  222. return (m_fScreenFlags & VGUI_SCREEN_VISIBLE_TO_TEAMMATES) != 0;
  223. }
  224. void CVGuiScreen::MakeVisibleOnlyToTeammates( bool bActive )
  225. {
  226. if (bActive != IsVisibleOnlyToTeammates())
  227. {
  228. if (!bActive)
  229. {
  230. m_fScreenFlags &= ~VGUI_SCREEN_VISIBLE_TO_TEAMMATES;
  231. }
  232. else
  233. {
  234. m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_VISIBLE_TO_TEAMMATES );
  235. }
  236. }
  237. }
  238. bool CVGuiScreen::IsVisibleToTeam( int nTeam )
  239. {
  240. // FIXME: Should this maybe go into a derived class of some sort?
  241. // Don't bother with screens on the wrong team
  242. if ( IsVisibleOnlyToTeammates() && (nTeam > 0) )
  243. {
  244. // Hmmm... sort of a hack...
  245. CBaseEntity *pOwner = GetOwnerEntity();
  246. if ( pOwner && (nTeam != pOwner->GetTeamNumber()) )
  247. return false;
  248. }
  249. return true;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose: Screens attached to view models only go to client if viewmodel is being sent, too.
  253. // Input : *recipient -
  254. // *pvs -
  255. // clientArea -
  256. // Output : Returns true on success, false on failure.
  257. //-----------------------------------------------------------------------------
  258. int CVGuiScreen::UpdateTransmitState()
  259. {
  260. if ( IsAttachedToViewModel() )
  261. {
  262. // only send to the owner, or someone spectating the owner.
  263. return SetTransmitState( FL_EDICT_FULLCHECK );
  264. }
  265. else if ( GetMoveParent() )
  266. {
  267. // Let the parent object trigger the send. This is more efficient than having it call CBaseEntity::ShouldTransmit
  268. // for all the vgui screens in the map.
  269. return SetTransmitState( FL_EDICT_PVSCHECK );
  270. }
  271. else
  272. {
  273. return BaseClass::UpdateTransmitState();
  274. }
  275. }
  276. int CVGuiScreen::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  277. {
  278. Assert( IsAttachedToViewModel() );
  279. CBaseEntity *pViewModel = GetOwnerEntity();
  280. if ( pViewModel )
  281. {
  282. return pViewModel->ShouldTransmit( pInfo );
  283. }
  284. return BaseClass::ShouldTransmit( pInfo );
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Convert the panel name into an integer
  288. //-----------------------------------------------------------------------------
  289. void CVGuiScreen::SetPanelName( const char *pPanelName )
  290. {
  291. m_nPanelName = g_pStringTableVguiScreen->AddString( CBaseEntity::IsServer(), pPanelName );
  292. }
  293. const char *CVGuiScreen::GetPanelName() const
  294. {
  295. return g_pStringTableVguiScreen->GetString( m_nPanelName );
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Sets the screen size + resolution
  299. //-----------------------------------------------------------------------------
  300. void CVGuiScreen::SetActualSize( float flWidth, float flHeight )
  301. {
  302. m_flWidth = flWidth;
  303. m_flHeight = flHeight;
  304. Vector mins, maxs;
  305. mins.Init( 0.0f, 0.0f, -0.1f );
  306. maxs.Init( 0.0f, 0.0f, 0.1f );
  307. if (flWidth > 0)
  308. maxs.x = flWidth;
  309. else
  310. mins.x = flWidth;
  311. if (flHeight > 0)
  312. maxs.y = flHeight;
  313. else
  314. mins.y = flHeight;
  315. UTIL_SetSize( this, mins, maxs );
  316. }
  317. //-----------------------------------------------------------------------------
  318. //
  319. //-----------------------------------------------------------------------------
  320. void CVGuiScreen::SetPlayerOwner( CBasePlayer *pPlayer, bool bOwnerOnlyInput /* = false */ )
  321. {
  322. m_hPlayerOwner = pPlayer;
  323. if ( bOwnerOnlyInput )
  324. {
  325. m_fScreenFlags.Set( VGUI_SCREEN_ONLY_USABLE_BY_OWNER );
  326. }
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Precaches a vgui screen
  330. //-----------------------------------------------------------------------------
  331. void PrecacheVGuiScreen( const char *pScreenType )
  332. {
  333. g_pStringTableVguiScreen->AddString( CBaseEntity::IsServer(), pScreenType );
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Creates a vgui screen, attaches it to another player
  337. //-----------------------------------------------------------------------------
  338. CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex )
  339. {
  340. Assert( pAttachedTo );
  341. CVGuiScreen *pScreen = (CVGuiScreen *)CBaseEntity::Create( pScreenClassname, vec3_origin, vec3_angle, pAttachedTo );
  342. pScreen->SetPanelName( pScreenType );
  343. pScreen->FollowEntity( pAttachedTo );
  344. pScreen->SetOwnerEntity( pOwner );
  345. pScreen->SetAttachmentIndex( nAttachmentIndex );
  346. return pScreen;
  347. }
  348. void DestroyVGuiScreen( CVGuiScreen *pVGuiScreen )
  349. {
  350. if (pVGuiScreen)
  351. {
  352. UTIL_Remove( pVGuiScreen );
  353. }
  354. }