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.

657 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <mxtk/mx.h>
  9. #include <stdio.h>
  10. #include "resource.h"
  11. #include "EventProperties.h"
  12. #include "mdlviewer.h"
  13. #include "choreoevent.h"
  14. #include "choreoscene.h"
  15. #include "mathlib/mathlib.h"
  16. #include "choreochannel.h"
  17. #include "choreoactor.h"
  18. #include "filesystem.h"
  19. #include "scriplib.h"
  20. #include "eventproperties_expression.h"
  21. #include "eventproperties_face.h"
  22. #include "eventproperties_firetrigger.h"
  23. #include "eventproperties_flexanimation.h"
  24. #include "eventproperties_generic.h"
  25. #include "eventproperties_gesture.h"
  26. #include "eventproperties_interrupt.h"
  27. #include "eventproperties_lookat.h"
  28. #include "eventproperties_moveto.h"
  29. #include "eventproperties_permitresponses.h"
  30. #include "eventproperties_sequence.h"
  31. #include "eventproperties_speak.h"
  32. #include "eventproperties_subscene.h"
  33. void CBaseEventPropertiesDialog::PopulateTagList( CEventParams *params )
  34. {
  35. CChoreoScene *scene = params->m_pScene;
  36. if ( !scene )
  37. return;
  38. HWND control = GetControl( IDC_TAGS );
  39. if ( control )
  40. {
  41. SendMessage( control, CB_RESETCONTENT, 0, 0 );
  42. SendMessage( control, WM_SETTEXT , 0, (LPARAM)va( "\"%s\" \"%s\"", params->m_szTagName, params->m_szTagWav ) );
  43. for ( int i = 0; i < scene->GetNumActors(); i++ )
  44. {
  45. CChoreoActor *a = scene->GetActor( i );
  46. if ( !a )
  47. continue;
  48. for ( int j = 0; j < a->GetNumChannels(); j++ )
  49. {
  50. CChoreoChannel *c = a->GetChannel( j );
  51. if ( !c )
  52. continue;
  53. for ( int k = 0 ; k < c->GetNumEvents(); k++ )
  54. {
  55. CChoreoEvent *e = c->GetEvent( k );
  56. if ( !e )
  57. continue;
  58. if ( e->GetNumRelativeTags() <= 0 )
  59. continue;
  60. // add each tag to combo box
  61. for ( int t = 0; t < e->GetNumRelativeTags(); t++ )
  62. {
  63. CEventRelativeTag *tag = e->GetRelativeTag( t );
  64. if ( !tag )
  65. continue;
  66. SendMessage( control, CB_ADDSTRING, 0, (LPARAM)va( "\"%s\" \"%s\"", tag->GetName(), e->GetParameters() ) );
  67. }
  68. }
  69. }
  70. }
  71. }
  72. }
  73. #include "mapentities.h"
  74. #include "utldict.h"
  75. struct CMapEntityData
  76. {
  77. CMapEntityData()
  78. {
  79. origin.Init();
  80. angles.Init();
  81. }
  82. Vector origin;
  83. QAngle angles;
  84. };
  85. class CMapEntities : public IMapEntities
  86. {
  87. public:
  88. CMapEntities();
  89. ~CMapEntities();
  90. virtual void CheckUpdateMap( char const *mapname );
  91. virtual bool LookupOrigin( char const *name, Vector& origin, QAngle& angles )
  92. {
  93. int idx = FindNamedEntity( name );
  94. if ( idx == -1 )
  95. {
  96. origin.Init();
  97. angles.Init();
  98. return false;
  99. }
  100. CMapEntityData *e = &m_Entities[ idx ];
  101. Assert( e );
  102. origin = e->origin;
  103. angles = e->angles;
  104. return true;
  105. }
  106. virtual int Count( void );
  107. virtual char const *GetName( int number );
  108. int FindNamedEntity( char const *name );
  109. private:
  110. char m_szCurrentMap[ 1024 ];
  111. CUtlDict< CMapEntityData, int > m_Entities;
  112. };
  113. static CMapEntities g_MapEntities;
  114. // Expose to rest of tool
  115. IMapEntities *mapentities = &g_MapEntities;
  116. CMapEntities::CMapEntities()
  117. {
  118. m_szCurrentMap[ 0 ] = 0;
  119. }
  120. CMapEntities::~CMapEntities()
  121. {
  122. m_Entities.RemoveAll();
  123. }
  124. int CMapEntities::FindNamedEntity( char const *name )
  125. {
  126. char lowername[ 128 ];
  127. strcpy( lowername, name );
  128. _strlwr( lowername );
  129. int index = m_Entities.Find( lowername );
  130. if ( index == m_Entities.InvalidIndex() )
  131. return -1;
  132. return index;
  133. }
  134. #include "bspfile.h"
  135. void CMapEntities::CheckUpdateMap( char const *mapname )
  136. {
  137. if ( !mapname || !mapname[ 0 ] )
  138. return;
  139. if ( !stricmp( mapname, m_szCurrentMap ) )
  140. return;
  141. // Latch off the name of the map
  142. Q_strncpy( m_szCurrentMap, mapname, sizeof( m_szCurrentMap ) );
  143. // Load names from map
  144. m_Entities.RemoveAll();
  145. FileHandle_t hfile = filesystem->Open( mapname, "rb" );
  146. if ( hfile == FILESYSTEM_INVALID_HANDLE )
  147. return;
  148. dheader_t header;
  149. filesystem->Read( &header, sizeof( header ), hfile );
  150. // Check the header
  151. if ( header.ident != IDBSPHEADER ||
  152. header.version < MINBSPVERSION || header.version > BSPVERSION )
  153. {
  154. Con_ErrorPrintf( "BSP file %s is wrong version (%i), expected (%i)\n",
  155. mapname,
  156. header.version,
  157. BSPVERSION );
  158. filesystem->Close( hfile );
  159. return;
  160. }
  161. // Find the LUMP_PAKFILE offset
  162. lump_t *entlump = &header.lumps[ LUMP_ENTITIES ];
  163. if ( entlump->filelen <= 0 )
  164. {
  165. Con_ErrorPrintf( "BSP file %s is missing entity lump\n", mapname );
  166. // It's empty or only contains a file header ( so there are no entries ), so don't add to search paths
  167. filesystem->Close( hfile );
  168. return;
  169. }
  170. // Seek to correct position
  171. filesystem->Seek( hfile, entlump->fileofs, FILESYSTEM_SEEK_HEAD );
  172. char *buffer = new char[ entlump->filelen + 1 ];
  173. Assert( buffer );
  174. filesystem->Read( buffer, entlump->filelen, hfile );
  175. filesystem->Close( hfile );
  176. buffer[ entlump->filelen ] = 0;
  177. // Now we have entity buffer, now parse it
  178. ParseFromMemory( buffer, entlump->filelen );
  179. while ( 1 )
  180. {
  181. if (!GetToken (true))
  182. break;
  183. if (Q_stricmp (token, "{") )
  184. Error ("ParseEntity: { not found");
  185. char name[ 256 ];
  186. char origin[ 256 ];
  187. char angles[ 256 ];
  188. name[ 0 ] = 0;
  189. origin[ 0 ] = 0;
  190. angles[ 0 ] = 0;
  191. do
  192. {
  193. char key[ 256 ];
  194. char value[ 256 ];
  195. if (!GetToken (true))
  196. {
  197. Error ("ParseEntity: EOF without closing brace");
  198. }
  199. if (!Q_stricmp (token, "}") )
  200. break;
  201. Q_strncpy( key, token, sizeof( key ) );
  202. GetToken (false);
  203. Q_strncpy( value, token, sizeof( value ) );
  204. // Con_Printf( "Parsed %s -- %s\n", key, value );
  205. if ( !Q_stricmp( key, "name" ) )
  206. {
  207. Q_strncpy( name, value, sizeof( name ) );
  208. }
  209. if ( !Q_stricmp( key, "targetname" ) )
  210. {
  211. Q_strncpy( name, value, sizeof( name ) );
  212. }
  213. if ( !Q_stricmp( key, "origin" ) )
  214. {
  215. Q_strncpy( origin, value, sizeof( origin ) );
  216. }
  217. if ( !Q_stricmp( key, "angles" ) )
  218. {
  219. Q_strncpy( angles, value, sizeof( angles ) );
  220. }
  221. } while (1);
  222. if ( name[ 0 ] )
  223. {
  224. if ( FindNamedEntity( name ) == - 1 )
  225. {
  226. CMapEntityData ent;
  227. float org[3];
  228. if ( origin[ 0 ] )
  229. {
  230. if ( 3 == sscanf( origin, "%f %f %f", &org[ 0 ], &org[ 1 ], &org[ 2 ] ) )
  231. {
  232. ent.origin = Vector( org[ 0 ], org[ 1 ], org[ 2 ] );
  233. // Con_Printf( "read %f %f %f for entity %s\n", org[0], org[1], org[2], name );
  234. }
  235. }
  236. if ( angles[ 0 ] )
  237. {
  238. if ( 3 == sscanf( angles, "%f %f %f", &org[ 0 ], &org[ 1 ], &org[ 2 ] ) )
  239. {
  240. ent.angles = QAngle( org[ 0 ], org[ 1 ], org[ 2 ] );
  241. // Con_Printf( "read %f %f %f for entity %s\n", org[0], org[1], org[2], name );
  242. }
  243. }
  244. m_Entities.Insert( name, ent );
  245. }
  246. }
  247. }
  248. delete[] buffer;
  249. }
  250. int CMapEntities::Count( void )
  251. {
  252. return m_Entities.Count();
  253. }
  254. char const *CMapEntities::GetName( int number )
  255. {
  256. if ( number < 0 || number >= (int)m_Entities.Count() )
  257. return NULL;
  258. return m_Entities.GetElementName( number );
  259. }
  260. bool NameLessFunc( const char *const& name1, const char *const& name2 )
  261. {
  262. if ( Q_stricmp( name1, name2 ) < 0 )
  263. return true;
  264. return false;
  265. }
  266. void CBaseEventPropertiesDialog::SetDialogTitle( CEventParams *params, char const *eventname, char const *desc )
  267. {
  268. char sz[ 256 ];
  269. Q_snprintf( sz, sizeof( sz ), " : %s", eventname );
  270. Q_strncat( params->m_szDialogTitle, sz, sizeof( params->m_szDialogTitle ), COPY_ALL_CHARACTERS );
  271. Q_snprintf( sz, sizeof( sz ), "%s:", desc );
  272. // Set dialog title
  273. SetWindowText( m_hDialog, params->m_szDialogTitle );
  274. // Set type name field
  275. SetDlgItemText( m_hDialog, IDC_TYPENAME, sz );
  276. // Set event name
  277. SetDlgItemText( m_hDialog, IDC_EVENTNAME, params->m_szName );
  278. }
  279. void CBaseEventPropertiesDialog::ShowControlsForEventType( CEventParams *params )
  280. {
  281. // Special processing for various settings
  282. if ( !params->m_bHasEndTime )
  283. {
  284. ShowWindow( GetControl( IDC_ENDTIME ), SW_HIDE );
  285. }
  286. if ( params->m_bFixedLength )
  287. {
  288. ShowWindow( GetControl( IDC_ENDTIME ), SW_HIDE );
  289. ShowWindow( GetControl( IDC_CHECK_ENDTIME ), SW_HIDE );
  290. }
  291. }
  292. void CBaseEventPropertiesDialog::InitControlData( CEventParams *params )
  293. {
  294. SetDlgItemText( m_hDialog, IDC_STARTTIME, va( "%f", params->m_flStartTime ) );
  295. SetDlgItemText( m_hDialog, IDC_ENDTIME, va( "%f", params->m_flEndTime ) );
  296. SendMessage( GetControl( IDC_CHECK_ENDTIME ), BM_SETCHECK,
  297. ( WPARAM ) params->m_bHasEndTime ? BST_CHECKED : BST_UNCHECKED,
  298. ( LPARAM )0 );
  299. if ( GetControl( IDC_CHECK_RESUMECONDITION ) != (HWND)0 )
  300. {
  301. SendMessage( GetControl( IDC_CHECK_RESUMECONDITION ), BM_SETCHECK,
  302. ( WPARAM ) params->m_bResumeCondition ? BST_CHECKED : BST_UNCHECKED,
  303. ( LPARAM )0 );
  304. }
  305. SendMessage( GetControl( IDC_CHECK_DISABLED ), BM_SETCHECK,
  306. ( WPARAM ) params->m_bDisabled ? BST_CHECKED : BST_UNCHECKED,
  307. ( LPARAM )0 );
  308. PopulateTagList( params );
  309. }
  310. BOOL CBaseEventPropertiesDialog::InternalHandleMessage( CEventParams *params, HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& handled )
  311. {
  312. handled = false;
  313. switch(uMsg)
  314. {
  315. default:
  316. break;
  317. case WM_COMMAND:
  318. switch (LOWORD(wParam))
  319. {
  320. default:
  321. break;
  322. case IDC_CHECK_DISABLED:
  323. {
  324. params->m_bDisabled = SendMessage( GetControl( IDC_CHECK_DISABLED ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ? true : false;
  325. handled = true;
  326. return TRUE;
  327. }
  328. break;
  329. }
  330. }
  331. return FALSE;
  332. }
  333. void CBaseEventPropertiesDialog::PopulateNamedActorList( HWND wnd, CEventParams *params )
  334. {
  335. int i;
  336. char const *mapname = NULL;
  337. if ( params->m_pScene )
  338. {
  339. mapname = params->m_pScene->GetMapname();
  340. }
  341. CUtlRBTree< char const *, int > m_SortedNames( 0, 0, NameLessFunc );
  342. if ( mapname )
  343. {
  344. g_MapEntities.CheckUpdateMap( mapname );
  345. for ( i = 0; i < g_MapEntities.Count(); i++ )
  346. {
  347. char const *name = g_MapEntities.GetName( i );
  348. if ( name && name[ 0 ] )
  349. {
  350. m_SortedNames.Insert( name );
  351. }
  352. }
  353. }
  354. for ( i = 0 ; i < params->m_pScene->GetNumActors() ; i++ )
  355. {
  356. CChoreoActor *actor = params->m_pScene->GetActor( i );
  357. if ( actor && actor->GetName() && actor->GetName()[0] )
  358. {
  359. if ( m_SortedNames.Find( actor->GetName() ) == m_SortedNames.InvalidIndex() )
  360. {
  361. m_SortedNames.Insert( actor->GetName() );
  362. }
  363. }
  364. }
  365. i = m_SortedNames.FirstInorder();
  366. while ( i != m_SortedNames.InvalidIndex() )
  367. {
  368. char const *name = m_SortedNames[ i ];
  369. if ( name && name[ 0 ] )
  370. {
  371. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)name );
  372. }
  373. i = m_SortedNames.NextInorder( i );
  374. }
  375. /*
  376. // Note have to do this here, after posting data to the control, since we are storing a raw string pointer in m_SortedNames!!!
  377. if ( allActors )
  378. {
  379. allActors->deleteThis();
  380. }
  381. */
  382. // These events can also be directed at another player or named target, too
  383. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!player" );
  384. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!enemy" );
  385. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!self" );
  386. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!friend" );
  387. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!speechtarget" );
  388. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target1" );
  389. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target2" );
  390. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target3" );
  391. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target4" );
  392. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target5" );
  393. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target6" );
  394. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target7" );
  395. SendMessage( wnd, CB_ADDSTRING, 0, (LPARAM)"!target8" );
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Purpose:
  399. // Input : wnd -
  400. // *params -
  401. // Output : static void
  402. //-----------------------------------------------------------------------------
  403. void CBaseEventPropertiesDialog::ParseTags( CEventParams *params )
  404. {
  405. strcpy( params->m_szTagName, "" );
  406. strcpy( params->m_szTagWav, "" );
  407. if ( params->m_bUsesTag )
  408. {
  409. // Parse out the two tokens
  410. char selectedText[ 512 ];
  411. selectedText[ 0 ] = 0;
  412. HWND control = GetControl( IDC_TAGS );
  413. if ( control )
  414. {
  415. SendMessage( control, WM_GETTEXT, (WPARAM)sizeof( selectedText ), (LPARAM)selectedText );
  416. }
  417. ParseFromMemory( selectedText, strlen( selectedText ) );
  418. if ( TokenAvailable() )
  419. {
  420. GetToken( false );
  421. char tagname[ 256 ];
  422. strcpy( tagname, token );
  423. if ( TokenAvailable() )
  424. {
  425. GetToken( false );
  426. char wavename[ 256 ];
  427. strcpy( wavename, token );
  428. // Valid
  429. strcpy( params->m_szTagName, tagname );
  430. strcpy( params->m_szTagWav, wavename );
  431. }
  432. else
  433. {
  434. params->m_bUsesTag = false;
  435. }
  436. }
  437. else
  438. {
  439. params->m_bUsesTag = false;
  440. }
  441. }
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Purpose:
  445. // Input : wnd -
  446. // *params -
  447. // Output : static void
  448. //-----------------------------------------------------------------------------
  449. void CBaseEventPropertiesDialog::UpdateTagRadioButtons( CEventParams *params )
  450. {
  451. if ( params->m_bUsesTag )
  452. {
  453. SendMessage( GetControl( IDC_RELATIVESTART ), BM_SETCHECK, ( WPARAM )BST_CHECKED, (LPARAM)0 );
  454. SendMessage( GetControl( IDC_ABSOLUTESTART ), BM_SETCHECK, ( WPARAM )BST_UNCHECKED, (LPARAM)0 );
  455. }
  456. else
  457. {
  458. SendMessage( GetControl( IDC_ABSOLUTESTART ), BM_SETCHECK, ( WPARAM )BST_CHECKED, (LPARAM)0 );
  459. SendMessage( GetControl( IDC_RELATIVESTART ), BM_SETCHECK, ( WPARAM )BST_UNCHECKED, (LPARAM)0 );
  460. }
  461. }
  462. void CBaseEventPropertiesDialog::GetSplineRect( HWND placeholder, RECT& rcOut )
  463. {
  464. GetWindowRect( placeholder, &rcOut );
  465. RECT rcDlg;
  466. GetWindowRect( m_hDialog, &rcDlg );
  467. OffsetRect( &rcOut, -rcDlg.left, -rcDlg.top );
  468. }
  469. void CBaseEventPropertiesDialog::DrawSpline( HDC hdc, HWND placeholder, CChoreoEvent *e )
  470. {
  471. RECT rcOut;
  472. GetSplineRect( placeholder, rcOut );
  473. HBRUSH bg = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
  474. FillRect( hdc, &rcOut, bg );
  475. DeleteObject( bg );
  476. if ( !e )
  477. return;
  478. // Draw spline
  479. float range = ( float )( rcOut.right - rcOut.left );
  480. if ( range <= 1.0f )
  481. return;
  482. float height = ( float )( rcOut.bottom - rcOut.top );
  483. HPEN pen = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_BTNTEXT ) );
  484. HPEN oldPen = (HPEN)SelectObject( hdc, pen );
  485. float duration = e->GetDuration();
  486. float starttime = e->GetStartTime();
  487. for ( int i = 0; i < (int)range; i++ )
  488. {
  489. float frac = ( float )i / ( range - 1 );
  490. float scale = 1.0f - e->GetIntensity( starttime + frac * duration );
  491. int h = ( int ) ( scale * ( height - 1 ) );
  492. if ( i == 0 )
  493. {
  494. MoveToEx( hdc, rcOut.left + i, rcOut.top + h, NULL );
  495. }
  496. else
  497. {
  498. LineTo( hdc, rcOut.left + i, rcOut.top + h );
  499. }
  500. }
  501. SelectObject( hdc, oldPen );
  502. HBRUSH frame = CreateSolidBrush( GetSysColor( COLOR_BTNSHADOW ) );
  503. InflateRect( &rcOut, 1, 1 );
  504. FrameRect( hdc, &rcOut, frame );
  505. DeleteObject( frame );
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. // Input : *view -
  510. // *actor -
  511. // Output : int
  512. //-----------------------------------------------------------------------------
  513. int EventProperties( CEventParams *params )
  514. {
  515. int iret = 1;
  516. switch ( params->m_nType )
  517. {
  518. default:
  519. break;
  520. case CChoreoEvent::EXPRESSION:
  521. return EventProperties_Expression( params );
  522. case CChoreoEvent::LOOKAT:
  523. return EventProperties_LookAt( params );
  524. case CChoreoEvent::MOVETO:
  525. return EventProperties_MoveTo( params );
  526. case CChoreoEvent::SPEAK:
  527. return EventProperties_Speak( params );
  528. case CChoreoEvent::GESTURE:
  529. return EventProperties_Gesture( params );
  530. case CChoreoEvent::SEQUENCE:
  531. return EventProperties_Sequence( params );
  532. case CChoreoEvent::FACE:
  533. return EventProperties_Face( params );
  534. case CChoreoEvent::FIRETRIGGER:
  535. return EventProperties_FireTrigger( params );
  536. case CChoreoEvent::FLEXANIMATION:
  537. return EventProperties_FlexAnimation( params );
  538. case CChoreoEvent::SUBSCENE:
  539. return EventProperties_SubScene( params );
  540. case CChoreoEvent::INTERRUPT:
  541. return EventProperties_Interrupt( params );
  542. case CChoreoEvent::PERMIT_RESPONSES:
  543. return EventProperties_PermitResponses( params );
  544. case CChoreoEvent::GENERIC:
  545. return EventProperties_Generic( params );
  546. }
  547. return iret;
  548. }