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.

624 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the big scary boom-boom machine Antlions fear.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "EnvMessage.h"
  8. #include "fmtstr.h"
  9. #include "vguiscreen.h"
  10. #include "filesystem.h"
  11. #define SLIDESHOW_LIST_BUFFER_MAX 8192
  12. struct SlideKeywordList_t
  13. {
  14. char szSlideKeyword[64];
  15. };
  16. class CSlideshowDisplay : public CBaseEntity
  17. {
  18. public:
  19. DECLARE_CLASS( CSlideshowDisplay, CBaseEntity );
  20. DECLARE_DATADESC();
  21. DECLARE_SERVERCLASS();
  22. virtual ~CSlideshowDisplay();
  23. virtual bool KeyValue( const char *szKeyName, const char *szValue );
  24. virtual int UpdateTransmitState();
  25. virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
  26. virtual void Spawn( void );
  27. virtual void Precache( void );
  28. virtual void OnRestore( void );
  29. void ScreenVisible( bool bVisible );
  30. void Disable( void );
  31. void Enable( void );
  32. void InputDisable( inputdata_t &inputdata );
  33. void InputEnable( inputdata_t &inputdata );
  34. void InputSetDisplayText( inputdata_t &inputdata );
  35. void InputRemoveAllSlides( inputdata_t &inputdata );
  36. void InputAddSlides( inputdata_t &inputdata );
  37. void InputSetMinSlideTime( inputdata_t &inputdata );
  38. void InputSetMaxSlideTime( inputdata_t &inputdata );
  39. void InputSetCycleType( inputdata_t &inputdata );
  40. void InputSetNoListRepeats( inputdata_t &inputdata );
  41. private:
  42. // Control panel
  43. void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
  44. void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName );
  45. void SpawnControlPanels( void );
  46. void RestoreControlPanels( void );
  47. void BuildSlideShowImagesList( void );
  48. private:
  49. CNetworkVar( bool, m_bEnabled );
  50. CNetworkString( m_szDisplayText, 128 );
  51. CNetworkString( m_szSlideshowDirectory, 128 );
  52. string_t m_String_tSlideshowDirectory;
  53. CUtlVector<SlideKeywordList_t*> m_SlideKeywordList;
  54. CNetworkArray( unsigned char, m_chCurrentSlideLists, 16 );
  55. CNetworkVar( float, m_fMinSlideTime );
  56. CNetworkVar( float, m_fMaxSlideTime );
  57. CNetworkVar( int, m_iCycleType );
  58. CNetworkVar( bool, m_bNoListRepeats );
  59. int m_iScreenWidth;
  60. int m_iScreenHeight;
  61. bool m_bDoFullTransmit;
  62. typedef CHandle<CVGuiScreen> ScreenHandle_t;
  63. CUtlVector<ScreenHandle_t> m_hScreens;
  64. };
  65. LINK_ENTITY_TO_CLASS( vgui_slideshow_display, CSlideshowDisplay );
  66. //-----------------------------------------------------------------------------
  67. // Save/load
  68. //-----------------------------------------------------------------------------
  69. BEGIN_DATADESC( CSlideshowDisplay )
  70. DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
  71. DEFINE_AUTO_ARRAY_KEYFIELD( m_szDisplayText, FIELD_CHARACTER, "displaytext" ),
  72. DEFINE_AUTO_ARRAY( m_szSlideshowDirectory, FIELD_CHARACTER ),
  73. DEFINE_KEYFIELD( m_String_tSlideshowDirectory, FIELD_STRING, "directory" ),
  74. // DEFINE_FIELD( m_SlideKeywordList, CUtlVector < SlideKeywordList_t* > ),
  75. DEFINE_AUTO_ARRAY( m_chCurrentSlideLists, FIELD_CHARACTER ),
  76. DEFINE_KEYFIELD( m_fMinSlideTime, FIELD_FLOAT, "minslidetime" ),
  77. DEFINE_KEYFIELD( m_fMaxSlideTime, FIELD_FLOAT, "maxslidetime" ),
  78. DEFINE_KEYFIELD( m_iCycleType, FIELD_INTEGER, "cycletype" ),
  79. DEFINE_KEYFIELD( m_bNoListRepeats, FIELD_BOOLEAN, "nolistrepeats" ),
  80. DEFINE_KEYFIELD( m_iScreenWidth, FIELD_INTEGER, "width" ),
  81. DEFINE_KEYFIELD( m_iScreenHeight, FIELD_INTEGER, "height" ),
  82. //DEFINE_FIELD( m_bDoFullTransmit, FIELD_BOOLEAN ),
  83. //DEFINE_UTLVECTOR( m_hScreens, FIELD_EHANDLE ),
  84. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  85. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  86. DEFINE_INPUTFUNC( FIELD_STRING, "SetDisplayText", InputSetDisplayText ),
  87. DEFINE_INPUTFUNC( FIELD_VOID, "RemoveAllSlides", InputRemoveAllSlides ),
  88. DEFINE_INPUTFUNC( FIELD_STRING, "AddSlides", InputAddSlides ),
  89. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetMinSlideTime", InputSetMinSlideTime ),
  90. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetMaxSlideTime", InputSetMaxSlideTime ),
  91. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCycleType", InputSetCycleType ),
  92. DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetNoListRepeats", InputSetNoListRepeats ),
  93. END_DATADESC()
  94. IMPLEMENT_SERVERCLASS_ST( CSlideshowDisplay, DT_SlideshowDisplay )
  95. SendPropBool( SENDINFO(m_bEnabled) ),
  96. SendPropString( SENDINFO( m_szDisplayText ) ),
  97. SendPropString( SENDINFO( m_szSlideshowDirectory ) ),
  98. SendPropArray3( SENDINFO_ARRAY3(m_chCurrentSlideLists), SendPropInt( SENDINFO_ARRAY(m_chCurrentSlideLists), 8, SPROP_UNSIGNED ) ),
  99. SendPropFloat( SENDINFO(m_fMinSlideTime), 11, 0, 0.0f, 20.0f ),
  100. SendPropFloat( SENDINFO(m_fMaxSlideTime), 11, 0, 0.0f, 20.0f ),
  101. SendPropInt( SENDINFO(m_iCycleType), 2, SPROP_UNSIGNED ),
  102. SendPropBool( SENDINFO(m_bNoListRepeats) ),
  103. END_SEND_TABLE()
  104. CSlideshowDisplay::~CSlideshowDisplay()
  105. {
  106. int i;
  107. // Kill the control panels
  108. for ( i = m_hScreens.Count(); --i >= 0; )
  109. {
  110. DestroyVGuiScreen( m_hScreens[i].Get() );
  111. }
  112. m_hScreens.RemoveAll();
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Read in worldcraft data...
  116. //-----------------------------------------------------------------------------
  117. bool CSlideshowDisplay::KeyValue( const char *szKeyName, const char *szValue )
  118. {
  119. //!! temp hack, until worldcraft is fixed
  120. // strip the # tokens from (duplicate) key names
  121. char *s = (char *)strchr( szKeyName, '#' );
  122. if ( s )
  123. {
  124. *s = '\0';
  125. }
  126. // NOTE: Have to do these separate because they set two values instead of one
  127. if( FStrEq( szKeyName, "angles" ) )
  128. {
  129. Assert( GetMoveParent() == NULL );
  130. QAngle angles;
  131. UTIL_StringToVector( angles.Base(), szValue );
  132. // Because the vgui screen basis is strange (z is front, y is up, x is right)
  133. // we need to rotate the typical basis before applying it
  134. VMatrix mat, rotation, tmp;
  135. MatrixFromAngles( angles, mat );
  136. MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 );
  137. MatrixMultiply( mat, rotation, tmp );
  138. MatrixBuildRotateZ( rotation, 90 );
  139. MatrixMultiply( tmp, rotation, mat );
  140. MatrixToAngles( mat, angles );
  141. SetAbsAngles( angles );
  142. return true;
  143. }
  144. return BaseClass::KeyValue( szKeyName, szValue );
  145. }
  146. int CSlideshowDisplay::UpdateTransmitState()
  147. {
  148. if ( m_bDoFullTransmit )
  149. {
  150. m_bDoFullTransmit = false;
  151. return SetTransmitState( FL_EDICT_ALWAYS );
  152. }
  153. return SetTransmitState( FL_EDICT_FULLCHECK );
  154. }
  155. void CSlideshowDisplay::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
  156. {
  157. // Are we already marked for transmission?
  158. if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
  159. return;
  160. BaseClass::SetTransmit( pInfo, bAlways );
  161. // Force our screens to be sent too.
  162. for ( int i=0; i < m_hScreens.Count(); i++ )
  163. {
  164. CVGuiScreen *pScreen = m_hScreens[i].Get();
  165. pScreen->SetTransmit( pInfo, bAlways );
  166. }
  167. }
  168. void CSlideshowDisplay::Spawn( void )
  169. {
  170. Q_strcpy( m_szSlideshowDirectory.GetForModify(), m_String_tSlideshowDirectory.ToCStr() );
  171. Precache();
  172. BaseClass::Spawn();
  173. m_bEnabled = false;
  174. // Clear out selected list
  175. m_chCurrentSlideLists.GetForModify( 0 ) = 0; // Select all slides to begin with
  176. for ( int i = 1; i < 16; ++i )
  177. m_chCurrentSlideLists.GetForModify( i ) = (unsigned char)-1;
  178. SpawnControlPanels();
  179. ScreenVisible( m_bEnabled );
  180. m_bDoFullTransmit = true;
  181. }
  182. void CSlideshowDisplay::Precache( void )
  183. {
  184. BaseClass::Precache();
  185. BuildSlideShowImagesList();
  186. PrecacheVGuiScreen( "slideshow_display_screen" );
  187. }
  188. void CSlideshowDisplay::OnRestore( void )
  189. {
  190. BaseClass::OnRestore();
  191. BuildSlideShowImagesList();
  192. RestoreControlPanels();
  193. ScreenVisible( m_bEnabled );
  194. }
  195. void CSlideshowDisplay::ScreenVisible( bool bVisible )
  196. {
  197. for ( int iScreen = 0; iScreen < m_hScreens.Count(); ++iScreen )
  198. {
  199. CVGuiScreen *pScreen = m_hScreens[ iScreen ].Get();
  200. if ( bVisible )
  201. pScreen->RemoveEffects( EF_NODRAW );
  202. else
  203. pScreen->AddEffects( EF_NODRAW );
  204. }
  205. }
  206. void CSlideshowDisplay::Disable( void )
  207. {
  208. if ( !m_bEnabled )
  209. return;
  210. m_bEnabled = false;
  211. ScreenVisible( false );
  212. }
  213. void CSlideshowDisplay::Enable( void )
  214. {
  215. if ( m_bEnabled )
  216. return;
  217. m_bEnabled = true;
  218. ScreenVisible( true );
  219. }
  220. void CSlideshowDisplay::InputDisable( inputdata_t &inputdata )
  221. {
  222. Disable();
  223. }
  224. void CSlideshowDisplay::InputEnable( inputdata_t &inputdata )
  225. {
  226. Enable();
  227. }
  228. void CSlideshowDisplay::InputSetDisplayText( inputdata_t &inputdata )
  229. {
  230. Q_strcpy( m_szDisplayText.GetForModify(), inputdata.value.String() );
  231. }
  232. void CSlideshowDisplay::InputRemoveAllSlides( inputdata_t &inputdata )
  233. {
  234. // Clear out selected list
  235. for ( int i = 0; i < 16; ++i )
  236. m_chCurrentSlideLists.GetForModify( i ) = (unsigned char)-1;
  237. }
  238. void CSlideshowDisplay::InputAddSlides( inputdata_t &inputdata )
  239. {
  240. // Find the list with the current keyword
  241. int iList;
  242. for ( iList = 0; iList < m_SlideKeywordList.Count(); ++iList )
  243. {
  244. if ( Q_strcmp( m_SlideKeywordList[ iList ]->szSlideKeyword, inputdata.value.String() ) == 0 )
  245. break;
  246. }
  247. if ( iList < m_SlideKeywordList.Count() )
  248. {
  249. // Found the keyword list, so add this index to the selected lists
  250. int iNumCurrentSlideLists;
  251. for ( iNumCurrentSlideLists = 0; iNumCurrentSlideLists < 16; ++iNumCurrentSlideLists )
  252. {
  253. if ( m_chCurrentSlideLists[ iNumCurrentSlideLists ] == (unsigned char)-1 )
  254. break;
  255. }
  256. if ( iNumCurrentSlideLists >= 16 )
  257. return;
  258. m_chCurrentSlideLists.GetForModify( iNumCurrentSlideLists ) = iList;
  259. }
  260. }
  261. void CSlideshowDisplay::InputSetMinSlideTime( inputdata_t &inputdata )
  262. {
  263. m_fMinSlideTime = inputdata.value.Float();
  264. }
  265. void CSlideshowDisplay::InputSetMaxSlideTime( inputdata_t &inputdata )
  266. {
  267. m_fMaxSlideTime = inputdata.value.Float();
  268. }
  269. void CSlideshowDisplay::InputSetCycleType( inputdata_t &inputdata )
  270. {
  271. m_iCycleType = inputdata.value.Int();
  272. }
  273. void CSlideshowDisplay::InputSetNoListRepeats( inputdata_t &inputdata )
  274. {
  275. m_bNoListRepeats = inputdata.value.Bool();
  276. }
  277. void CSlideshowDisplay::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
  278. {
  279. pPanelName = "slideshow_display_screen";
  280. }
  281. void CSlideshowDisplay::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
  282. {
  283. pPanelName = "vgui_screen";
  284. }
  285. //-----------------------------------------------------------------------------
  286. // This is called by the base object when it's time to spawn the control panels
  287. //-----------------------------------------------------------------------------
  288. void CSlideshowDisplay::SpawnControlPanels()
  289. {
  290. int nPanel;
  291. for ( nPanel = 0; true; ++nPanel )
  292. {
  293. const char *pScreenName;
  294. GetControlPanelInfo( nPanel, pScreenName );
  295. if (!pScreenName)
  296. continue;
  297. const char *pScreenClassname;
  298. GetControlPanelClassName( nPanel, pScreenClassname );
  299. if ( !pScreenClassname )
  300. continue;
  301. float flWidth = m_iScreenWidth;
  302. float flHeight = m_iScreenHeight;
  303. CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, this, this, -1 );
  304. pScreen->ChangeTeam( GetTeamNumber() );
  305. pScreen->SetActualSize( flWidth, flHeight );
  306. pScreen->SetActive( true );
  307. pScreen->MakeVisibleOnlyToTeammates( false );
  308. pScreen->SetTransparency( true );
  309. int nScreen = m_hScreens.AddToTail( );
  310. m_hScreens[nScreen].Set( pScreen );
  311. return;
  312. }
  313. }
  314. void CSlideshowDisplay::RestoreControlPanels( void )
  315. {
  316. int nPanel;
  317. for ( nPanel = 0; true; ++nPanel )
  318. {
  319. const char *pScreenName;
  320. GetControlPanelInfo( nPanel, pScreenName );
  321. if (!pScreenName)
  322. continue;
  323. const char *pScreenClassname;
  324. GetControlPanelClassName( nPanel, pScreenClassname );
  325. if ( !pScreenClassname )
  326. continue;
  327. CVGuiScreen *pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( NULL, pScreenClassname );
  328. while ( ( pScreen && pScreen->GetOwnerEntity() != this ) || Q_strcmp( pScreen->GetPanelName(), pScreenName ) != 0 )
  329. {
  330. pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( pScreen, pScreenClassname );
  331. }
  332. if ( pScreen )
  333. {
  334. int nScreen = m_hScreens.AddToTail( );
  335. m_hScreens[nScreen].Set( pScreen );
  336. pScreen->SetActive( true );
  337. }
  338. return;
  339. }
  340. }
  341. void CSlideshowDisplay::BuildSlideShowImagesList( void )
  342. {
  343. FileFindHandle_t matHandle;
  344. char szDirectory[_MAX_PATH];
  345. char szMatFileName[_MAX_PATH] = {'\0'};
  346. char szFileBuffer[ SLIDESHOW_LIST_BUFFER_MAX ];
  347. char *pchCurrentLine = NULL;
  348. if ( IsX360() )
  349. {
  350. Q_snprintf( szDirectory, sizeof( szDirectory ), "materials/vgui/%s/slides.txt", m_szSlideshowDirectory.Get() );
  351. FileHandle_t fh = g_pFullFileSystem->Open( szDirectory, "rt" );
  352. if ( !fh )
  353. {
  354. DevWarning( "Couldn't read slideshow image file %s!", szDirectory );
  355. return;
  356. }
  357. int iFileSize = MIN( g_pFullFileSystem->Size( fh ), SLIDESHOW_LIST_BUFFER_MAX );
  358. int iBytesRead = g_pFullFileSystem->Read( szFileBuffer, iFileSize, fh );
  359. g_pFullFileSystem->Close( fh );
  360. // Ensure we don't write outside of our buffer
  361. if ( iBytesRead > iFileSize )
  362. iBytesRead = iFileSize;
  363. szFileBuffer[ iBytesRead ] = '\0';
  364. pchCurrentLine = szFileBuffer;
  365. // Seek to end of first line
  366. char *pchNextLine = pchCurrentLine;
  367. while ( *pchNextLine != '\0' && *pchNextLine != '\n' && *pchNextLine != ' ' )
  368. ++pchNextLine;
  369. if ( *pchNextLine != '\0' )
  370. {
  371. // Mark end of string
  372. *pchNextLine = '\0';
  373. // Seek to start of next string
  374. ++pchNextLine;
  375. while ( *pchNextLine != '\0' && ( *pchNextLine == '\n' || *pchNextLine == ' ' ) )
  376. ++pchNextLine;
  377. }
  378. Q_strncpy( szMatFileName, pchCurrentLine, sizeof(szMatFileName) );
  379. pchCurrentLine = pchNextLine;
  380. }
  381. else
  382. {
  383. Q_snprintf( szDirectory, sizeof( szDirectory ), "materials/vgui/%s/*.vmt", m_szSlideshowDirectory.Get() );
  384. const char *pMatFileName = g_pFullFileSystem->FindFirst( szDirectory, &matHandle );
  385. if ( pMatFileName )
  386. Q_strncpy( szMatFileName, pMatFileName, sizeof(szMatFileName) );
  387. }
  388. int iSlideIndex = 0;
  389. while ( szMatFileName[ 0 ] )
  390. {
  391. char szFileName[_MAX_PATH];
  392. Q_snprintf( szFileName, sizeof( szFileName ), "vgui/%s/%s", m_szSlideshowDirectory.Get(), szMatFileName );
  393. szFileName[ Q_strlen( szFileName ) - 4 ] = '\0';
  394. PrecacheMaterial( szFileName );
  395. // Get material keywords
  396. char szFullFileName[_MAX_PATH];
  397. Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory.Get(), szMatFileName );
  398. KeyValues *pMaterialKeys = new KeyValues( "material" );
  399. bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL );
  400. if ( bLoaded )
  401. {
  402. char szKeywords[ 256 ] = {0};
  403. V_strcpy_safe( szKeywords, pMaterialKeys->GetString( "%keywords", "" ) );
  404. char *pchKeyword = szKeywords;
  405. while ( pchKeyword[ 0 ] != '\0' )
  406. {
  407. char *pNextKeyword = pchKeyword;
  408. // Skip commas and spaces
  409. while ( pNextKeyword[ 0 ] != '\0' && pNextKeyword[ 0 ] != ',' )
  410. ++pNextKeyword;
  411. if ( pNextKeyword[ 0 ] != '\0' )
  412. {
  413. pNextKeyword[ 0 ] = '\0';
  414. ++pNextKeyword;
  415. while ( pNextKeyword[ 0 ] != '\0' && ( pNextKeyword[ 0 ] == ',' || pNextKeyword[ 0 ] == ' ' ) )
  416. ++pNextKeyword;
  417. }
  418. // Find the list with the current keyword
  419. int iList;
  420. for ( iList = 0; iList < m_SlideKeywordList.Count(); ++iList )
  421. {
  422. if ( Q_strcmp( m_SlideKeywordList[ iList ]->szSlideKeyword, pchKeyword ) == 0 )
  423. break;
  424. }
  425. if ( iList >= m_SlideKeywordList.Count() )
  426. {
  427. // Couldn't find the list, so create it
  428. iList = m_SlideKeywordList.AddToTail( new SlideKeywordList_t );
  429. V_strcpy_safe( m_SlideKeywordList[iList]->szSlideKeyword, pchKeyword );
  430. }
  431. pchKeyword = pNextKeyword;
  432. }
  433. }
  434. // Find the generic list
  435. int iList;
  436. for ( iList = 0; iList < m_SlideKeywordList.Count(); ++iList )
  437. {
  438. if ( Q_strcmp( m_SlideKeywordList[ iList ]->szSlideKeyword, "" ) == 0 )
  439. break;
  440. }
  441. if ( iList >= m_SlideKeywordList.Count() )
  442. {
  443. // Couldn't find the generic list, so create it
  444. iList = m_SlideKeywordList.AddToHead( new SlideKeywordList_t );
  445. V_strcpy_safe( m_SlideKeywordList[iList]->szSlideKeyword, "" );
  446. }
  447. if ( IsX360() )
  448. {
  449. // Seek to end of first line
  450. char *pchNextLine = pchCurrentLine;
  451. while ( *pchNextLine != '\0' && *pchNextLine != '\n' && *pchNextLine != ' ' )
  452. ++pchNextLine;
  453. if ( *pchNextLine != '\0' )
  454. {
  455. // Mark end of string
  456. *pchNextLine = '\0';
  457. // Seek to start of next string
  458. ++pchNextLine;
  459. while ( *pchNextLine != '\0' && ( *pchNextLine == '\n' || *pchNextLine == ' ' ) )
  460. ++pchNextLine;
  461. }
  462. Q_strncpy( szMatFileName, pchCurrentLine, sizeof(szMatFileName) );
  463. pchCurrentLine = pchNextLine;
  464. }
  465. else
  466. {
  467. const char *pMatFileName = g_pFullFileSystem->FindNext( matHandle );
  468. if ( pMatFileName )
  469. Q_strncpy( szMatFileName, pMatFileName, sizeof(szMatFileName) );
  470. else
  471. szMatFileName[ 0 ] = '\0';
  472. }
  473. ++iSlideIndex;
  474. }
  475. if ( !IsX360() )
  476. {
  477. g_pFullFileSystem->FindClose( matHandle );
  478. }
  479. }