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.

645 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "client_pch.h"
  8. #include "cl_demoaction.h"
  9. #include "cl_demoactionmanager.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //-----------------------------------------------------------------------------
  13. // Purpose:
  14. //-----------------------------------------------------------------------------
  15. CBaseDemoAction::CBaseDemoAction()
  16. {
  17. }
  18. //-----------------------------------------------------------------------------
  19. // Purpose:
  20. //-----------------------------------------------------------------------------
  21. CBaseDemoAction::~CBaseDemoAction()
  22. {
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Purpose:
  26. // Output : DEMOACTION
  27. //-----------------------------------------------------------------------------
  28. DEMOACTION CBaseDemoAction::GetType( void ) const
  29. {
  30. return m_Type;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose:
  34. // Input : actionType -
  35. //-----------------------------------------------------------------------------
  36. void CBaseDemoAction::SetType( DEMOACTION actionType )
  37. {
  38. m_Type = actionType;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. // Output : DEMOACTIONTIMINGTYPE
  43. //-----------------------------------------------------------------------------
  44. DEMOACTIONTIMINGTYPE CBaseDemoAction::GetTimingType( void ) const
  45. {
  46. return m_Timing;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. // Input : timingtype -
  51. //-----------------------------------------------------------------------------
  52. void CBaseDemoAction::SetTimingType( DEMOACTIONTIMINGTYPE timingtype )
  53. {
  54. m_Timing = timingtype;
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. // Input : fired -
  59. //-----------------------------------------------------------------------------
  60. void CBaseDemoAction::SetActionFired( bool fired )
  61. {
  62. m_bActionFired = fired;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. // Output : Returns true on success, false on failure.
  67. //-----------------------------------------------------------------------------
  68. bool CBaseDemoAction::GetActionFired( void ) const
  69. {
  70. return m_bActionFired;
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose:
  74. //-----------------------------------------------------------------------------
  75. void CBaseDemoAction::SetFinishedAction( bool finished )
  76. {
  77. m_bActionFinished = finished;
  78. if ( finished )
  79. {
  80. OnActionFinished();
  81. }
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose:
  85. // Output : Returns true on success, false on failure.
  86. //-----------------------------------------------------------------------------
  87. bool CBaseDemoAction::HasActionFinished( void ) const
  88. {
  89. return m_bActionFinished;
  90. }
  91. #include "tier0/memdbgoff.h"
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. // Input : sz -
  95. // Output : void *CBaseDemoAction::operator
  96. //-----------------------------------------------------------------------------
  97. void *CBaseDemoAction::operator new( size_t sz )
  98. {
  99. Assert( sz != 0 );
  100. return calloc( 1, sz );
  101. };
  102. //-----------------------------------------------------------------------------
  103. // Purpose:
  104. // Input : *pMem -
  105. // Output : void CBaseDemoAction::operator
  106. //-----------------------------------------------------------------------------
  107. void CBaseDemoAction::operator delete( void *pMem )
  108. {
  109. #if defined( WIN32 ) && defined( _DEBUG )
  110. // set the memory to a known value
  111. int size = _msize( pMem );
  112. Q_memset( pMem, 0xcd, size );
  113. #endif
  114. // get the engine to free the memory
  115. free( pMem );
  116. }
  117. #include "tier0/memdbgon.h"
  118. //-----------------------------------------------------------------------------
  119. // Purpose:
  120. //-----------------------------------------------------------------------------
  121. struct DemoActionDictionary
  122. {
  123. DEMOACTION actiontype;;
  124. char const *name;
  125. DEMOACTIONFACTORY_FUNC func;
  126. DEMOACTIONEDIT_FUNC editfunc;
  127. };
  128. static DemoActionDictionary g_rgDemoTypeNames[ NUM_DEMO_ACTIONS ] =
  129. {
  130. { DEMO_ACTION_UNKNOWN , "Unknown" },
  131. { DEMO_ACTION_SKIPAHEAD , "SkipAhead" },
  132. { DEMO_ACTION_STOPPLAYBACK , "StopPlayback" },
  133. { DEMO_ACTION_PLAYCOMMANDS , "PlayCommands" },
  134. { DEMO_ACTION_SCREENFADE_START , "ScreenFadeStart" },
  135. { DEMO_ACTION_SCREENFADE_STOP , "ScreenFadeStop" },
  136. { DEMO_ACTION_TEXTMESSAGE_START , "TextMessageStart" },
  137. { DEMO_ACTION_TEXTMESSAGE_STOP , "TextMessageStop" },
  138. { DEMO_ACTION_PLAYCDTRACK_START , "PlayCDTrackStart" },
  139. { DEMO_ACTION_PLAYCDTRACK_STOP , "PlayCDTrackStop" },
  140. { DEMO_ACTION_PLAYSOUND_START , "PlaySoundStart" },
  141. { DEMO_ACTION_PLAYSOUND_END , "PlaySoundStop" },
  142. { DEMO_ACTION_ONSKIPPEDAHEAD , "OnSkippedAhead" },
  143. { DEMO_ACTION_ONSTOPPEDPLAYBACK , "OnStoppedPlayback" },
  144. { DEMO_ACTION_ONSCREENFADE_FINISHED , "OnScreenFadeFinished" },
  145. { DEMO_ACTION_ONTEXTMESSAGE_FINISHED , "OnTextMessageFinished" },
  146. { DEMO_ACTION_ONPLAYCDTRACK_FINISHED , "OnPlayCDTrackFinished" },
  147. { DEMO_ACTION_ONPLAYSOUND_FINISHED , "OnPlaySoundFinished" },
  148. { DEMO_ACTION_PAUSE , "Pause" },
  149. { DEMO_ACTION_CHANGEPLAYBACKRATE , "ChangePlaybackRate" },
  150. { DEMO_ACTION_ZOOM , "Zoom FOV" },
  151. };
  152. //-----------------------------------------------------------------------------
  153. // Purpose:
  154. // Input : actionType -
  155. // func -
  156. //-----------------------------------------------------------------------------
  157. void CBaseDemoAction::AddFactory( DEMOACTION actionType, DEMOACTIONFACTORY_FUNC func )
  158. {
  159. int idx = (int)actionType;
  160. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  161. {
  162. Sys_Error( "CBaseDemoAction::AddFactory: Bogus factory type %i\n", idx );
  163. return;
  164. }
  165. g_rgDemoTypeNames[ idx ].func = func;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. // Input : actionType -
  170. //-----------------------------------------------------------------------------
  171. CBaseDemoAction *CBaseDemoAction::CreateDemoAction( DEMOACTION actionType )
  172. {
  173. int idx = (int)actionType;
  174. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  175. {
  176. Sys_Error( "CBaseDemoAction::AddFactory: Bogus factory type %i\n", idx );
  177. return NULL;
  178. }
  179. DEMOACTIONFACTORY_FUNC pfn = g_rgDemoTypeNames[ idx ].func;
  180. if ( !pfn )
  181. {
  182. ConMsg( "CBaseDemoAction::CreateDemoAction: Missing factory for %s\n",
  183. NameForType( actionType ) );
  184. return NULL;
  185. }
  186. return (*pfn)();
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose:
  190. // Input : actionType -
  191. // func -
  192. //-----------------------------------------------------------------------------
  193. void CBaseDemoAction::AddEditorFactory( DEMOACTION actionType, DEMOACTIONEDIT_FUNC func )
  194. {
  195. int idx = (int)actionType;
  196. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  197. {
  198. Sys_Error( "CBaseDemoAction::AddEditorFactory: Bogus factory type %i\n", idx );
  199. return;
  200. }
  201. g_rgDemoTypeNames[ idx ].editfunc = func;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. // Input : actionType -
  206. // *parent -
  207. // *action -
  208. // newaction -
  209. // Output : CBaseActionEditDialog
  210. //-----------------------------------------------------------------------------
  211. CBaseActionEditDialog *CBaseDemoAction::CreateActionEditor( DEMOACTION actionType, CDemoEditorPanel *parent, CBaseDemoAction *action, bool newaction )
  212. {
  213. int idx = (int)actionType;
  214. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  215. {
  216. Sys_Error( "CBaseDemoAction::AddFactory: Bogus factory type %i\n", idx );
  217. return NULL;
  218. }
  219. DEMOACTIONEDIT_FUNC pfn = g_rgDemoTypeNames[ idx ].editfunc;
  220. if ( !pfn )
  221. {
  222. ConMsg( "CBaseDemoAction::CreateActionEditor: Missing edit factory for %s\n",
  223. NameForType( actionType ) );
  224. return NULL;
  225. }
  226. return (*pfn)( parent, action, newaction );
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Purpose:
  230. // Input : actionType -
  231. // Output : Returns true on success, false on failure.
  232. //-----------------------------------------------------------------------------
  233. bool CBaseDemoAction::HasEditorFactory( DEMOACTION actionType )
  234. {
  235. int idx = (int)actionType;
  236. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  237. {
  238. return false;
  239. }
  240. DEMOACTIONEDIT_FUNC pfn = g_rgDemoTypeNames[ idx ].editfunc;
  241. if ( !pfn )
  242. {
  243. return false;
  244. }
  245. return true;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose:
  249. //-----------------------------------------------------------------------------
  250. struct DemoTimingTagDictionary
  251. {
  252. DEMOACTIONTIMINGTYPE timingtype;;
  253. char const *name;
  254. };
  255. static DemoTimingTagDictionary g_rgDemoTimingTypeNames[ NUM_TIMING_TYPES ] =
  256. {
  257. { ACTION_USES_NEITHER , "TimeDontCare" },
  258. { ACTION_USES_TICK , "TimeUseTick" },
  259. { ACTION_USES_TIME , "TimeUseClock" },
  260. };
  261. //-----------------------------------------------------------------------------
  262. // Purpose:
  263. // Input : DEMOACTION -
  264. // Output : char const
  265. //-----------------------------------------------------------------------------
  266. char const *CBaseDemoAction::NameForType( DEMOACTION actionType )
  267. {
  268. int idx = (int)actionType;
  269. if ( idx < 0 || idx >= NUM_DEMO_ACTIONS )
  270. {
  271. ConMsg( "ERROR: CBaseDemoAction::NameForType type %i out of range\n", idx );
  272. return g_rgDemoTypeNames[ DEMO_ACTION_UNKNOWN ].name;
  273. }
  274. DemoActionDictionary *entry = &g_rgDemoTypeNames[ idx ];
  275. Assert( entry->actiontype == actionType );
  276. return entry->name;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose:
  280. // Input : *name -
  281. // Output : DEMOACTION
  282. //-----------------------------------------------------------------------------
  283. DEMOACTION CBaseDemoAction::TypeForName( char const *name )
  284. {
  285. int c = NUM_DEMO_ACTIONS;
  286. int i;
  287. for ( i= 0; i < c; i++ )
  288. {
  289. DemoActionDictionary *entry = &g_rgDemoTypeNames[ i ];
  290. if ( !Q_strcasecmp( entry->name, name ) )
  291. {
  292. return entry->actiontype;
  293. }
  294. }
  295. return DEMO_ACTION_UNKNOWN;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. // Input : DEMOACTION -
  300. // Output : char const
  301. //-----------------------------------------------------------------------------
  302. char const *CBaseDemoAction::NameForTimingType( DEMOACTIONTIMINGTYPE timingType )
  303. {
  304. int idx = (int)timingType;
  305. if ( idx < 0 || idx >= NUM_TIMING_TYPES )
  306. {
  307. ConMsg( "ERROR: CBaseDemoAction::NameForTimingType type %i out of range\n", idx );
  308. return g_rgDemoTimingTypeNames[ ACTION_USES_NEITHER ].name;
  309. }
  310. DemoTimingTagDictionary *entry = &g_rgDemoTimingTypeNames[ idx ];
  311. Assert( entry->timingtype == timingType );
  312. return entry->name;
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose:
  316. // Input : *name -
  317. // Output : DEMOACTION
  318. //-----------------------------------------------------------------------------
  319. DEMOACTIONTIMINGTYPE CBaseDemoAction::TimingTypeForName( char const *name )
  320. {
  321. int c = NUM_TIMING_TYPES;
  322. int i;
  323. for ( i= 0; i < c; i++ )
  324. {
  325. DemoTimingTagDictionary *entry = &g_rgDemoTimingTypeNames[ i ];
  326. if ( !Q_strcasecmp( entry->name, name ) )
  327. {
  328. return entry->timingtype;
  329. }
  330. }
  331. return ACTION_USES_NEITHER;
  332. }
  333. static bool g_bSaveChained = false;
  334. //-----------------------------------------------------------------------------
  335. // Purpose: Simple printf wrapper which handles tab characters
  336. // Input : buf -
  337. // *fmt -
  338. // ... -
  339. //-----------------------------------------------------------------------------
  340. void CBaseDemoAction::BufPrintf( int depth, CUtlBuffer& buf, char const *fmt, ... )
  341. {
  342. va_list argptr;
  343. char string[1024];
  344. va_start (argptr,fmt);
  345. Q_vsnprintf(string, sizeof( string ), fmt,argptr);
  346. va_end (argptr);
  347. while ( depth-- > 0 )
  348. {
  349. buf.Printf( "\t" );
  350. }
  351. buf.Printf( "%s", string );
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose:
  355. // Input : buf -
  356. //-----------------------------------------------------------------------------
  357. void CBaseDemoAction::SaveKeysToBuffer( int depth, CUtlBuffer& buf )
  358. {
  359. // All derived actions will need to do a BaseClass::SaveKeysToBuffer call
  360. g_bSaveChained = true;
  361. BufPrintf( depth, buf, "name \"%s\"\n", GetActionName() );
  362. if ( ActionHasTarget() )
  363. {
  364. BufPrintf( depth, buf, "target \"%s\"\n", GetActionTarget() );
  365. }
  366. switch ( GetTimingType() )
  367. {
  368. default:
  369. case ACTION_USES_NEITHER:
  370. break;
  371. case ACTION_USES_TICK:
  372. {
  373. BufPrintf( depth, buf, "starttick \"%i\"\n", GetStartTick() );
  374. }
  375. break;
  376. case ACTION_USES_TIME:
  377. {
  378. BufPrintf( depth, buf, "starttime \"%.3f\"\n", GetStartTime() );
  379. }
  380. break;
  381. }
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Purpose:
  385. // Input : buf -
  386. //-----------------------------------------------------------------------------
  387. void CBaseDemoAction::SaveToBuffer( int depth, int index, CUtlBuffer& buf )
  388. {
  389. // Store index
  390. BufPrintf( depth, buf, "\"%i\"\n", index );
  391. BufPrintf( depth, buf, "%{\n" );
  392. g_bSaveChained = false;
  393. // First key is factory name
  394. BufPrintf( depth + 1, buf, "factory \"%s\"\n", NameForType( GetType() ) );
  395. SaveKeysToBuffer( depth + 1, buf );
  396. Assert( g_bSaveChained );
  397. BufPrintf( depth, buf, "}\n" );
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. // Input : *name -
  402. //-----------------------------------------------------------------------------
  403. void CBaseDemoAction::SetActionName( char const *name )
  404. {
  405. Q_strncpy( m_szActionName, name, sizeof( m_szActionName ) );
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose: Parse root data
  409. // Input : *pInitData -
  410. // Output : Returns true on success, false on failure.
  411. //-----------------------------------------------------------------------------
  412. bool CBaseDemoAction::Init( KeyValues *pInitData )
  413. {
  414. char const *actionname = pInitData->GetString( "name", "" );
  415. if ( !actionname || !actionname[ 0 ] )
  416. {
  417. Msg( "CBaseDemoAction::Init: must specify a name for action!\n" );
  418. return false;
  419. }
  420. SetActionName( actionname );
  421. m_nStartTick = pInitData->GetInt( "starttick", -1 );
  422. m_flStartTime = pInitData->GetFloat( "starttime", -1.0f );
  423. if ( m_nStartTick == -1 && m_flStartTime == -1.0f )
  424. {
  425. m_Timing = ACTION_USES_NEITHER;
  426. }
  427. else if ( m_nStartTick != -1 )
  428. {
  429. m_Timing = ACTION_USES_TICK;
  430. }
  431. else
  432. {
  433. Assert( m_flStartTime != -1.0f );
  434. m_Timing = ACTION_USES_TIME;
  435. }
  436. // See if there's a target name
  437. char const *target = pInitData->GetString( "target", "" );
  438. if ( target && target[ 0 ] )
  439. {
  440. Q_strncpy( m_szActionTarget, target, sizeof( m_szActionTarget ) );
  441. }
  442. return true;
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose:
  446. // Output : int
  447. //-----------------------------------------------------------------------------
  448. int CBaseDemoAction::GetStartTick( void ) const
  449. {
  450. Assert( m_Timing == ACTION_USES_TICK );
  451. return m_nStartTick;
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. // Output : float
  456. //-----------------------------------------------------------------------------
  457. float CBaseDemoAction::GetStartTime( void ) const
  458. {
  459. Assert( m_Timing == ACTION_USES_TIME );
  460. return m_flStartTime;
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. // Input : frame -
  465. //-----------------------------------------------------------------------------
  466. void CBaseDemoAction::SetStartTick( int tick )
  467. {
  468. Assert( m_Timing == ACTION_USES_TICK );
  469. m_nStartTick = tick;
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Purpose:
  473. // Input : t -
  474. //-----------------------------------------------------------------------------
  475. void CBaseDemoAction::SetStartTime( float t )
  476. {
  477. Assert( m_Timing == ACTION_USES_TIME );
  478. m_flStartTime = t;
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Purpose:
  482. // Input : demoframe -
  483. // demotime -
  484. //-----------------------------------------------------------------------------
  485. bool CBaseDemoAction::Update( const DemoActionTimingContext& tc )
  486. {
  487. // Already fired and done?
  488. if ( HasActionFinished() )
  489. {
  490. Assert( GetActionFired() );
  491. return false;
  492. }
  493. // Already fired, just waiting for finished tag
  494. if ( GetActionFired() )
  495. {
  496. return true;
  497. }
  498. // See if it's time to fire
  499. switch ( GetTimingType() )
  500. {
  501. default:
  502. case ACTION_USES_NEITHER:
  503. return false;
  504. case ACTION_USES_TICK:
  505. {
  506. if ( GetStartTick() >= tc.prevtick && GetStartTick() <= tc.curtick )
  507. {
  508. demoaction->InsertFireEvent( this );
  509. }
  510. }
  511. break;
  512. case ACTION_USES_TIME:
  513. {
  514. if ( GetStartTime() >= tc.prevtime && GetStartTime() <= tc.curtime )
  515. {
  516. demoaction->InsertFireEvent( this );
  517. }
  518. }
  519. break;
  520. }
  521. return true;
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose:
  525. // Output : char const
  526. //-----------------------------------------------------------------------------
  527. char const *CBaseDemoAction::GetActionName( void ) const
  528. {
  529. Assert( m_szActionName[ 0 ] );
  530. return m_szActionName;
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose:
  534. // Output : Returns true on success, false on failure.
  535. //-----------------------------------------------------------------------------
  536. bool CBaseDemoAction::ActionHasTarget( void ) const
  537. {
  538. return m_szActionTarget[ 0 ] ? true : false;
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose:
  542. // Output : char const
  543. //-----------------------------------------------------------------------------
  544. char const *CBaseDemoAction::GetActionTarget( void ) const
  545. {
  546. Assert( ActionHasTarget() );
  547. return m_szActionTarget;
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Purpose:
  551. // Input : *name -
  552. //-----------------------------------------------------------------------------
  553. void CBaseDemoAction::SetActionTarget( char const *name )
  554. {
  555. Q_strncpy( m_szActionTarget, name, sizeof( m_szActionTarget ) );
  556. }
  557. //-----------------------------------------------------------------------------
  558. // Purpose: Restart timing info
  559. //-----------------------------------------------------------------------------
  560. void CBaseDemoAction::Reset( void )
  561. {
  562. SetActionFired( false );
  563. SetFinishedAction( false );
  564. }
  565. void CBaseDemoAction::OnActionFinished( void )
  566. {
  567. }