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.

2795 lines
78 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "animation.h"
  8. #include "baseflex.h"
  9. #include "filesystem.h"
  10. #include "studio.h"
  11. #include "choreoevent.h"
  12. #include "choreoscene.h"
  13. #include "choreoactor.h"
  14. #include "vstdlib/random.h"
  15. #include "engine/IEngineSound.h"
  16. #include "tier1/strtools.h"
  17. #include "KeyValues.h"
  18. #include "ai_basenpc.h"
  19. #include "ai_navigator.h"
  20. #include "ai_moveprobe.h"
  21. #include "sceneentity.h"
  22. #include "ai_baseactor.h"
  23. #include "datacache/imdlcache.h"
  24. #include "tier1/byteswap.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. static ConVar scene_showlook( "scene_showlook", "0", FCVAR_ARCHIVE, "When playing back, show the directions of look events." );
  28. static ConVar scene_showmoveto( "scene_showmoveto", "0", FCVAR_ARCHIVE, "When moving, show the end location." );
  29. static ConVar scene_showunlock( "scene_showunlock", "0", FCVAR_ARCHIVE, "Show when a vcd is playing but normal AI is running." );
  30. // static ConVar scene_checktagposition( "scene_checktagposition", "0", FCVAR_ARCHIVE, "When playing back a choreographed scene, check the current position of the tags relative to where they were authored." );
  31. // Fake layer # to force HandleProcessSceneEvent to actually allocate the layer during npc think time instead of in between.
  32. #define REQUEST_DEFERRED_LAYER_ALLOCATION -2
  33. extern bool g_bClientFlex;
  34. // ---------------------------------------------------------------------
  35. //
  36. // CBaseFlex -- physically simulated brush rectangular solid
  37. //
  38. // ---------------------------------------------------------------------
  39. void* SendProxy_FlexWeights( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  40. {
  41. // Don't any flexweights to client unless scene_clientflex.GetBool() is false
  42. if ( !g_bClientFlex )
  43. return (void*)pVarData;
  44. else
  45. return NULL;
  46. }
  47. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_FlexWeights );
  48. // SendTable stuff.
  49. IMPLEMENT_SERVERCLASS_ST(CBaseFlex, DT_BaseFlex)
  50. // Note we can't totally disabled flexweights transmission since some things like blink and eye tracking are still done by the server
  51. SendPropArray3 (SENDINFO_ARRAY3(m_flexWeight), SendPropFloat(SENDINFO_ARRAY(m_flexWeight), 12, SPROP_ROUNDDOWN, 0.0f, 1.0f ) /*, SendProxy_FlexWeights*/ ),
  52. SendPropInt (SENDINFO(m_blinktoggle), 1, SPROP_UNSIGNED ),
  53. SendPropVector (SENDINFO(m_viewtarget), -1, SPROP_COORD),
  54. #ifdef HL2_DLL
  55. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0), 0, SPROP_NOSCALE ),
  56. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1), 0, SPROP_NOSCALE ),
  57. SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2), 0, SPROP_NOSCALE ),
  58. SendPropVector ( SENDINFO(m_vecLean), -1, SPROP_COORD ),
  59. SendPropVector ( SENDINFO(m_vecShift), -1, SPROP_COORD ),
  60. #endif
  61. END_SEND_TABLE()
  62. BEGIN_DATADESC( CBaseFlex )
  63. // m_blinktoggle
  64. DEFINE_ARRAY( m_flexWeight, FIELD_FLOAT, MAXSTUDIOFLEXCTRL ),
  65. DEFINE_FIELD( m_viewtarget, FIELD_POSITION_VECTOR ),
  66. // m_SceneEvents
  67. // m_FileList
  68. DEFINE_FIELD( m_flAllowResponsesEndTime, FIELD_TIME ),
  69. // m_ActiveChoreoScenes
  70. // DEFINE_FIELD( m_LocalToGlobal, CUtlRBTree < FS_LocalToGlobal_t , unsigned short > ),
  71. // m_bUpdateLayerPriorities
  72. DEFINE_FIELD( m_flLastFlexAnimationTime, FIELD_TIME ),
  73. #ifdef HL2_DLL
  74. //DEFINE_FIELD( m_vecPrevOrigin, FIELD_POSITION_VECTOR ),
  75. //DEFINE_FIELD( m_vecPrevVelocity, FIELD_VECTOR ),
  76. DEFINE_FIELD( m_vecLean, FIELD_VECTOR ),
  77. DEFINE_FIELD( m_vecShift, FIELD_VECTOR ),
  78. #endif
  79. END_DATADESC()
  80. LINK_ENTITY_TO_CLASS( funCBaseFlex, CBaseFlex ); // meaningless independant class!!
  81. CBaseFlex::CBaseFlex( void ) :
  82. m_LocalToGlobal( 0, 0, FlexSettingLessFunc )
  83. {
  84. #ifdef _DEBUG
  85. // default constructor sets the viewtarget to NAN
  86. m_viewtarget.Init();
  87. #endif
  88. m_bUpdateLayerPriorities = true;
  89. m_flLastFlexAnimationTime = 0.0;
  90. }
  91. CBaseFlex::~CBaseFlex( void )
  92. {
  93. m_LocalToGlobal.RemoveAll();
  94. AssertMsg( m_SceneEvents.Count() == 0, "m_ScenesEvent.Count != 0: %d", m_SceneEvents.Count() );
  95. }
  96. void CBaseFlex::SetModel( const char *szModelName )
  97. {
  98. MDLCACHE_CRITICAL_SECTION();
  99. BaseClass::SetModel( szModelName );
  100. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  101. {
  102. SetFlexWeight( i, 0.0f );
  103. }
  104. }
  105. void CBaseFlex::SetViewtarget( const Vector &viewtarget )
  106. {
  107. m_viewtarget = viewtarget; // bah
  108. }
  109. void CBaseFlex::SetFlexWeight( LocalFlexController_t index, float value )
  110. {
  111. if (index >= 0 && index < GetNumFlexControllers())
  112. {
  113. CStudioHdr *pstudiohdr = GetModelPtr( );
  114. if (! pstudiohdr)
  115. return;
  116. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( index );
  117. if (pflexcontroller->max != pflexcontroller->min)
  118. {
  119. value = (value - pflexcontroller->min) / (pflexcontroller->max - pflexcontroller->min);
  120. value = clamp( value, 0.0f, 1.0f );
  121. }
  122. m_flexWeight.Set( index, value );
  123. }
  124. }
  125. float CBaseFlex::GetFlexWeight( LocalFlexController_t index )
  126. {
  127. if (index >= 0 && index < GetNumFlexControllers())
  128. {
  129. CStudioHdr *pstudiohdr = GetModelPtr( );
  130. if (! pstudiohdr)
  131. return 0;
  132. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( index );
  133. if (pflexcontroller->max != pflexcontroller->min)
  134. {
  135. return m_flexWeight[index] * (pflexcontroller->max - pflexcontroller->min) + pflexcontroller->min;
  136. }
  137. return m_flexWeight[index];
  138. }
  139. return 0.0;
  140. }
  141. LocalFlexController_t CBaseFlex::FindFlexController( const char *szName )
  142. {
  143. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  144. {
  145. if (stricmp( GetFlexControllerName( i ), szName ) == 0)
  146. {
  147. return i;
  148. }
  149. }
  150. // AssertMsg( 0, UTIL_VarArgs( "flexcontroller %s couldn't be mapped!!!\n", szName ) );
  151. return LocalFlexController_t(0);
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose:
  155. //-----------------------------------------------------------------------------
  156. void CBaseFlex::StartChoreoScene( CChoreoScene *scene )
  157. {
  158. if ( m_ActiveChoreoScenes.Find( scene ) != m_ActiveChoreoScenes.InvalidIndex() )
  159. {
  160. return;
  161. }
  162. m_ActiveChoreoScenes.AddToTail( scene );
  163. m_bUpdateLayerPriorities = true;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose:
  167. //-----------------------------------------------------------------------------
  168. void CBaseFlex::RemoveChoreoScene( CChoreoScene *scene, bool canceled )
  169. {
  170. // Assert( m_ActiveChoreoScenes.Find( scene ) != m_ActiveChoreoScenes.InvalidIndex() );
  171. m_ActiveChoreoScenes.FindAndRemove( scene );
  172. m_bUpdateLayerPriorities = true;
  173. if (canceled)
  174. {
  175. CAI_BaseNPC *myNpc = MyNPCPointer( );
  176. if ( myNpc )
  177. {
  178. myNpc->ClearSceneLock( );
  179. }
  180. }
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose:
  184. //-----------------------------------------------------------------------------
  185. int CBaseFlex::GetScenePriority( CChoreoScene *scene )
  186. {
  187. int iPriority = 0;
  188. int c = m_ActiveChoreoScenes.Count();
  189. // count number of channels in scenes older than current
  190. for ( int i = 0; i < c; i++ )
  191. {
  192. CChoreoScene *pScene = m_ActiveChoreoScenes[ i ];
  193. if ( !pScene )
  194. {
  195. continue;
  196. }
  197. if ( pScene == scene )
  198. {
  199. break;
  200. }
  201. iPriority += pScene->GetNumChannels( );
  202. }
  203. return iPriority;
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose: Remove all active SceneEvents
  207. //-----------------------------------------------------------------------------
  208. void CBaseFlex::ClearSceneEvents( CChoreoScene *scene, bool canceled )
  209. {
  210. if ( !scene )
  211. {
  212. m_SceneEvents.RemoveAll();
  213. return;
  214. }
  215. for ( int i = m_SceneEvents.Count() - 1; i >= 0; i-- )
  216. {
  217. CSceneEventInfo *info = &m_SceneEvents[ i ];
  218. Assert( info );
  219. Assert( info->m_pScene );
  220. Assert( info->m_pEvent );
  221. if ( info->m_pScene != scene )
  222. continue;
  223. if ( !ClearSceneEvent( info, false, canceled ))
  224. {
  225. // unknown expression to clear!!
  226. Assert( 0 );
  227. }
  228. // Free this slot
  229. info->m_pEvent = NULL;
  230. info->m_pScene = NULL;
  231. info->m_bStarted = false;
  232. m_SceneEvents.Remove( i );
  233. }
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Stop specifics of expression
  237. //-----------------------------------------------------------------------------
  238. bool CBaseFlex::ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled )
  239. {
  240. Assert( info );
  241. Assert( info->m_pScene );
  242. Assert( info->m_pEvent );
  243. // FIXME: this code looks duplicated
  244. switch ( info->m_pEvent->GetType() )
  245. {
  246. case CChoreoEvent::GESTURE:
  247. case CChoreoEvent::SEQUENCE:
  248. {
  249. if (info->m_iLayer >= 0)
  250. {
  251. if ( fastKill )
  252. {
  253. FastRemoveLayer( info->m_iLayer );
  254. }
  255. else if (info->m_pEvent->GetType() == CChoreoEvent::GESTURE)
  256. {
  257. if (canceled)
  258. {
  259. // remove slower if interrupted
  260. RemoveLayer( info->m_iLayer, 0.5 );
  261. }
  262. else
  263. {
  264. RemoveLayer( info->m_iLayer, 0.1 );
  265. }
  266. }
  267. else
  268. {
  269. RemoveLayer( info->m_iLayer, 0.3 );
  270. }
  271. }
  272. }
  273. return true;
  274. case CChoreoEvent::MOVETO:
  275. {
  276. CAI_BaseNPC *myNpc = MyNPCPointer( );
  277. if (!myNpc)
  278. return true;
  279. // cancel moveto if it's distance based, of if the event was part of a canceled vcd
  280. if (IsMoving() && (canceled || info->m_pEvent->GetDistanceToTarget() > 0.0))
  281. {
  282. if (!info->m_bHasArrived)
  283. {
  284. if (info->m_pScene)
  285. {
  286. Scene_Printf( "%s : %8.2f: MOVETO canceled but actor %s not at goal\n", info->m_pScene->GetFilename(), info->m_pScene->GetTime(), info->m_pEvent->GetActor()->GetName() );
  287. }
  288. }
  289. myNpc->GetNavigator()->StopMoving( false ); // Stop moving
  290. }
  291. }
  292. return true;
  293. case CChoreoEvent::FACE:
  294. case CChoreoEvent::FLEXANIMATION:
  295. case CChoreoEvent::EXPRESSION:
  296. case CChoreoEvent::LOOKAT:
  297. case CChoreoEvent::GENERIC:
  298. {
  299. // no special rules
  300. }
  301. return true;
  302. case CChoreoEvent::SPEAK:
  303. {
  304. // Tracker 15420: Issue stopsound if we need to cut this short...
  305. if ( canceled )
  306. {
  307. StopSound( info->m_pEvent->GetParameters() );
  308. #ifdef HL2_EPISODIC
  309. // If we were holding the semaphore because of this speech, release it
  310. CAI_BaseActor *pBaseActor = dynamic_cast<CAI_BaseActor*>(this);
  311. if ( pBaseActor )
  312. {
  313. pBaseActor->GetExpresser()->ForceNotSpeaking();
  314. }
  315. #endif
  316. }
  317. }
  318. return true;
  319. }
  320. return false;
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose: Add string indexed scene/expression/duration to list of active SceneEvents
  324. // Input : scenefile -
  325. // expression -
  326. // duration -
  327. //-----------------------------------------------------------------------------
  328. void CBaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget )
  329. {
  330. if ( !scene || !event )
  331. {
  332. Msg( "CBaseFlex::AddSceneEvent: scene or event was NULL!!!\n" );
  333. return;
  334. }
  335. CChoreoActor *actor = event->GetActor();
  336. if ( !actor )
  337. {
  338. Msg( "CBaseFlex::AddSceneEvent: event->GetActor() was NULL!!!\n" );
  339. return;
  340. }
  341. CSceneEventInfo info;
  342. memset( (void *)&info, 0, sizeof( info ) );
  343. info.m_pEvent = event;
  344. info.m_pScene = scene;
  345. info.m_hTarget = pTarget;
  346. info.m_bStarted = false;
  347. if (StartSceneEvent( &info, scene, event, actor, pTarget ))
  348. {
  349. m_SceneEvents.AddToTail( info );
  350. }
  351. else
  352. {
  353. Scene_Printf( "CBaseFlex::AddSceneEvent: event failed\n" );
  354. // Assert( 0 ); // expression failed to start
  355. }
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Starting various expression types
  359. //-----------------------------------------------------------------------------
  360. bool CBaseFlex::RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget )
  361. {
  362. info->m_nSequence = LookupSequence( event->GetParameters() );
  363. // make sure sequence exists
  364. if (info->m_nSequence < 0)
  365. {
  366. Warning( "CSceneEntity %s :\"%s\" unable to find sequence \"%s\"\n", STRING(GetEntityName()), actor->GetName(), event->GetParameters() );
  367. return false;
  368. }
  369. // This is a bit of a hack, but we need to defer the actual allocation until Process which will sync the layer allocation
  370. // to the NPCs think/m_flAnimTime instead of some arbitrary tick
  371. info->m_iLayer = REQUEST_DEFERRED_LAYER_ALLOCATION;
  372. info->m_pActor = actor;
  373. return true;
  374. }
  375. bool CBaseFlex::RequestStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget )
  376. {
  377. info->m_nSequence = LookupSequence( event->GetParameters() );
  378. // make sure sequence exists
  379. if (info->m_nSequence < 0)
  380. {
  381. Warning( "CSceneEntity %s :\"%s\" unable to find gesture \"%s\"\n", STRING(GetEntityName()), actor->GetName(), event->GetParameters() );
  382. return false;
  383. }
  384. // This is a bit of a hack, but we need to defer the actual allocation until Process which will sync the layer allocation
  385. // to the NPCs think/m_flAnimTime instead of some arbitrary tick
  386. info->m_iLayer = REQUEST_DEFERRED_LAYER_ALLOCATION;
  387. info->m_pActor = actor;
  388. return true;
  389. }
  390. bool CBaseFlex::HandleStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor )
  391. {
  392. Assert( info->m_iLayer == REQUEST_DEFERRED_LAYER_ALLOCATION );
  393. info->m_nSequence = LookupSequence( event->GetParameters() );
  394. info->m_iLayer = -1;
  395. if (info->m_nSequence < 0)
  396. {
  397. Warning( "CSceneEntity %s :\"%s\" unable to find sequence \"%s\"\n", STRING(GetEntityName()), actor->GetName(), event->GetParameters() );
  398. return false;
  399. }
  400. if (!EnterSceneSequence( scene, event ))
  401. {
  402. if (!event->GetPlayOverScript())
  403. {
  404. // this has failed to start
  405. Warning( "CSceneEntity %s :\"%s\" failed to start sequence \"%s\"\n", STRING(GetEntityName()), actor->GetName(), event->GetParameters() );
  406. return false;
  407. }
  408. // Start anyways, just use normal no-movement, must be in IDLE rules
  409. }
  410. info->m_iPriority = actor->FindChannelIndex( event->GetChannel() );
  411. info->m_iLayer = AddLayeredSequence( info->m_nSequence, info->m_iPriority + GetScenePriority( scene ) );
  412. SetLayerNoRestore( info->m_iLayer, true );
  413. SetLayerWeight( info->m_iLayer, 0.0 );
  414. bool looping = ((GetSequenceFlags( GetModelPtr(), info->m_nSequence ) & STUDIO_LOOPING) != 0);
  415. if (!looping)
  416. {
  417. // figure out the animtime when this was frame 0
  418. float dt = scene->GetTime() - event->GetStartTime();
  419. float seq_duration = SequenceDuration( info->m_nSequence );
  420. float flCycle = dt / seq_duration;
  421. flCycle = flCycle - (int)flCycle; // loop
  422. SetLayerCycle( info->m_iLayer, flCycle, flCycle, 0.f );
  423. SetLayerPlaybackRate( info->m_iLayer, 0.0 );
  424. }
  425. else
  426. {
  427. SetLayerPlaybackRate( info->m_iLayer, 1.0 );
  428. }
  429. if (IsMoving())
  430. {
  431. info->m_flWeight = 0.0;
  432. }
  433. else
  434. {
  435. info->m_flWeight = 1.0;
  436. }
  437. return true;
  438. }
  439. bool CBaseFlex::HandleStartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor )
  440. {
  441. Assert( info->m_iLayer == REQUEST_DEFERRED_LAYER_ALLOCATION );
  442. info->m_nSequence = LookupSequence( event->GetParameters() );
  443. info->m_iLayer = -1;
  444. if (info->m_nSequence < 0)
  445. {
  446. Warning( "CSceneEntity %s :\"%s\" unable to find gesture \"%s\"\n", STRING(GetEntityName()), actor->GetName(), event->GetParameters() );
  447. return false;
  448. }
  449. // FIXME: this seems like way too much code
  450. info->m_bIsGesture = false;
  451. KeyValues *seqKeyValues = GetSequenceKeyValues( info->m_nSequence );
  452. if (seqKeyValues)
  453. {
  454. // Do we have a build point section?
  455. KeyValues *pkvAllFaceposer = seqKeyValues->FindKey("faceposer");
  456. if ( pkvAllFaceposer )
  457. {
  458. KeyValues *pkvType = pkvAllFaceposer->FindKey("type");
  459. if (pkvType)
  460. {
  461. info->m_bIsGesture = (stricmp( pkvType->GetString(), "gesture" ) == 0) ? true : false;
  462. }
  463. }
  464. // FIXME: fixup tags that should be set as "linear", should be done in faceposer
  465. char szStartLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "loop" };
  466. char szEndLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
  467. // check in the tag indexes
  468. KeyValues *pkvFaceposer;
  469. for ( pkvFaceposer = pkvAllFaceposer->GetFirstSubKey(); pkvFaceposer; pkvFaceposer = pkvFaceposer->GetNextKey() )
  470. {
  471. if (!stricmp( pkvFaceposer->GetName(), "startloop" ))
  472. {
  473. V_strcpy_safe( szStartLoop, pkvFaceposer->GetString() );
  474. }
  475. else if (!stricmp( pkvFaceposer->GetName(), "endloop" ))
  476. {
  477. V_strcpy_safe( szEndLoop, pkvFaceposer->GetString() );
  478. }
  479. }
  480. CEventAbsoluteTag *ptag;
  481. ptag = event->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szStartLoop );
  482. if (ptag)
  483. {
  484. ptag->SetLinear( true );
  485. }
  486. ptag = event->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szStartLoop );
  487. if (ptag)
  488. {
  489. ptag->SetLinear( true );
  490. }
  491. ptag = event->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEndLoop );
  492. if (ptag)
  493. {
  494. ptag->SetLinear( true );
  495. }
  496. ptag = event->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEndLoop );
  497. if (ptag)
  498. {
  499. ptag->SetLinear( true );
  500. }
  501. if ( pkvAllFaceposer )
  502. {
  503. CStudioHdr *pstudiohdr = GetModelPtr();
  504. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( info->m_nSequence );
  505. mstudioanimdesc_t &animdesc = pstudiohdr->pAnimdesc( pstudiohdr->iRelativeAnim( info->m_nSequence, seqdesc.anim(0,0) ) );
  506. // check in the tag indexes
  507. KeyValues *pkvFaceposer;
  508. for ( pkvFaceposer = pkvAllFaceposer->GetFirstSubKey(); pkvFaceposer; pkvFaceposer = pkvFaceposer->GetNextKey() )
  509. {
  510. if (!stricmp( pkvFaceposer->GetName(), "tags" ))
  511. {
  512. KeyValues *pkvTags;
  513. for ( pkvTags = pkvFaceposer->GetFirstSubKey(); pkvTags; pkvTags = pkvTags->GetNextKey() )
  514. {
  515. int maxFrame = animdesc.numframes - 2; // FIXME: this is off by one!
  516. if ( maxFrame > 0)
  517. {
  518. float percentage = (float)pkvTags->GetInt() / maxFrame;
  519. CEventAbsoluteTag *ptag = event->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
  520. if (ptag)
  521. {
  522. if (fabs(ptag->GetPercentage() - percentage) > 0.05)
  523. {
  524. DevWarning("%s repositioned tag: %s : %.3f -> %.3f (%s:%s:%s)\n", scene->GetFilename(), pkvTags->GetName(), ptag->GetPercentage(), percentage, scene->GetFilename(), actor->GetName(), event->GetParameters() );
  525. // reposition tag
  526. ptag->SetPercentage( percentage );
  527. }
  528. }
  529. }
  530. }
  531. }
  532. }
  533. if (!event->VerifyTagOrder())
  534. {
  535. DevWarning("out of order tags : %s : (%s:%s:%s)\n", scene->GetFilename(), actor->GetName(), event->GetName(), event->GetParameters() );
  536. }
  537. }
  538. seqKeyValues->deleteThis();
  539. }
  540. // initialize posture suppression
  541. // FIXME: move priority of base animation so that layers can be inserted before
  542. // FIXME: query stopping, post idle layer to figure out correct weight
  543. // GetIdleLayerWeight()?
  544. if (!info->m_bIsGesture && IsMoving())
  545. {
  546. info->m_flWeight = 0.0;
  547. }
  548. else
  549. {
  550. info->m_flWeight = 1.0;
  551. }
  552. // this happens before StudioFrameAdvance()
  553. info->m_iPriority = actor->FindChannelIndex( event->GetChannel() );
  554. info->m_iLayer = AddLayeredSequence( info->m_nSequence, info->m_iPriority + GetScenePriority( scene ) );
  555. SetLayerNoRestore( info->m_iLayer, true );
  556. SetLayerDuration( info->m_iLayer, event->GetDuration() );
  557. SetLayerWeight( info->m_iLayer, 0.0 );
  558. bool looping = ((GetSequenceFlags( GetModelPtr(), info->m_nSequence ) & STUDIO_LOOPING) != 0);
  559. if ( looping )
  560. {
  561. DevMsg( 1, "vcd error, gesture %s of model %s is marked as STUDIO_LOOPING!\n",
  562. event->GetParameters(), STRING(GetModelName()) );
  563. }
  564. SetLayerLooping( info->m_iLayer, false ); // force to not loop
  565. float duration = event->GetDuration( );
  566. // figure out the animtime when this was frame 0
  567. float flEventCycle = (scene->GetTime() - event->GetStartTime()) / duration;
  568. float flCycle = event->GetOriginalPercentageFromPlaybackPercentage( flEventCycle );
  569. SetLayerCycle( info->m_iLayer, flCycle, 0.0 );
  570. SetLayerPlaybackRate( info->m_iLayer, 0.0 );
  571. return true;
  572. }
  573. bool CBaseFlex::StartFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget )
  574. {
  575. if ( pTarget )
  576. {
  577. // Don't allow FACE commands while sitting in the vehicle
  578. CAI_BaseNPC *myNpc = MyNPCPointer();
  579. if ( myNpc && myNpc->IsInAVehicle() )
  580. return false;
  581. info->m_bIsMoving = false;
  582. return true;
  583. }
  584. return false;
  585. }
  586. bool CBaseFlex::StartMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget )
  587. {
  588. if (pTarget)
  589. {
  590. info->m_bIsMoving = false;
  591. info->m_bHasArrived = false;
  592. CAI_BaseNPC *myNpc = MyNPCPointer( );
  593. if (!myNpc)
  594. {
  595. return false;
  596. }
  597. EnterSceneSequence( scene, event, true );
  598. // If they're already moving, stop them
  599. //
  600. // Don't stop them during restore because that will set a stopping path very
  601. // nearby, causing us to signal arrival prematurely in CheckSceneEventCompletion.
  602. // BEWARE: the behavior of this bug depended on the order in which the entities were restored!!
  603. if ( myNpc->IsMoving() && !scene->IsRestoring() )
  604. {
  605. myNpc->GetNavigator()->StopMoving( false );
  606. }
  607. return true;
  608. }
  609. return false;
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Purpose:
  613. //-----------------------------------------------------------------------------
  614. bool CBaseFlex::StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget )
  615. {
  616. switch ( event->GetType() )
  617. {
  618. case CChoreoEvent::SEQUENCE:
  619. return RequestStartSequenceSceneEvent( info, scene, event, actor, pTarget );
  620. case CChoreoEvent::GESTURE:
  621. return RequestStartGestureSceneEvent( info, scene, event, actor, pTarget );
  622. case CChoreoEvent::FACE:
  623. return StartFacingSceneEvent( info, scene, event, actor, pTarget );
  624. // FIXME: move this to an CBaseActor
  625. case CChoreoEvent::MOVETO:
  626. return StartMoveToSceneEvent( info, scene, event, actor, pTarget );
  627. case CChoreoEvent::LOOKAT:
  628. info->m_hTarget = pTarget;
  629. return true;
  630. case CChoreoEvent::FLEXANIMATION:
  631. info->InitWeight( this );
  632. return true;
  633. case CChoreoEvent::SPEAK:
  634. return true;
  635. case CChoreoEvent::EXPRESSION: // These are handled client-side
  636. return true;
  637. }
  638. return false;
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Purpose: Remove expression
  642. // Input : scenefile -
  643. // expression -
  644. //-----------------------------------------------------------------------------
  645. void CBaseFlex::RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill )
  646. {
  647. Assert( event );
  648. for ( int i = 0 ; i < m_SceneEvents.Count(); i++ )
  649. {
  650. CSceneEventInfo *info = &m_SceneEvents[ i ];
  651. Assert( info );
  652. Assert( info->m_pEvent );
  653. if ( info->m_pScene != scene )
  654. continue;
  655. if ( info->m_pEvent != event)
  656. continue;
  657. if (ClearSceneEvent( info, fastKill, false ))
  658. {
  659. // Free this slot
  660. info->m_pEvent = NULL;
  661. info->m_pScene = NULL;
  662. info->m_bStarted = false;
  663. m_SceneEvents.Remove( i );
  664. }
  665. }
  666. // many events refuse to start due to bogus parameters
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Purpose: Checks to see if the event should be considered "completed"
  670. //-----------------------------------------------------------------------------
  671. bool CBaseFlex::CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  672. {
  673. for ( int i = 0 ; i < m_SceneEvents.Count(); i++ )
  674. {
  675. CSceneEventInfo *info = &m_SceneEvents[ i ];
  676. Assert( info );
  677. Assert( info->m_pEvent );
  678. if ( info->m_pScene != scene )
  679. continue;
  680. if ( info->m_pEvent != event)
  681. continue;
  682. return CheckSceneEventCompletion( info, currenttime, scene, event );
  683. }
  684. return true;
  685. }
  686. bool CBaseFlex::CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  687. {
  688. switch ( event->GetType() )
  689. {
  690. case CChoreoEvent::MOVETO:
  691. {
  692. CAI_BaseNPC *npc = MyNPCPointer( );
  693. if (npc)
  694. {
  695. // check movement, check arrival
  696. if (npc->GetNavigator()->IsGoalActive())
  697. {
  698. const Task_t *pCurTask = npc->GetTask();
  699. if ( pCurTask && (pCurTask->iTask == TASK_PLAY_SCENE || pCurTask->iTask == TASK_WAIT_FOR_MOVEMENT ) )
  700. {
  701. float preload = event->GetEndTime() - currenttime;
  702. if (preload < 0)
  703. {
  704. //Msg("%.1f: no preload\n", currenttime );
  705. return false;
  706. }
  707. float t = npc->GetTimeToNavGoal();
  708. // Msg("%.1f: preload (%s:%.1f) %.1f %.1f\n", currenttime, event->GetName(), event->GetEndTime(), preload, t );
  709. // FIXME: t is zero if no path can be built!
  710. if (t > 0.0f && t <= preload)
  711. {
  712. return true;
  713. }
  714. return false;
  715. }
  716. }
  717. else if (info->m_bHasArrived)
  718. {
  719. return true;
  720. }
  721. else if (info->m_bStarted && !npc->IsCurSchedule( SCHED_SCENE_GENERIC ))
  722. {
  723. // FIXME: There's still a hole in the logic is the save happens immediately after the SS steals the npc but before their AI has run again
  724. Warning( "%s : %8.2f: waiting for actor %s to complete MOVETO but actor not in SCHED_SCENE_GENERIC\n", scene->GetFilename(), scene->GetTime(), event->GetActor()->GetName() );
  725. // no longer in a scene :P
  726. return true;
  727. }
  728. // still trying
  729. return false;
  730. }
  731. }
  732. break;
  733. default:
  734. break;
  735. }
  736. return true;
  737. }
  738. //-----------------------------------------------------------------------------
  739. // Purpose: Default implementation
  740. //-----------------------------------------------------------------------------
  741. void CBaseFlex::ProcessSceneEvents( void )
  742. {
  743. VPROF( "CBaseFlex::ProcessSceneEvents" );
  744. // slowly decay to netural expression
  745. for ( LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  746. {
  747. SetFlexWeight( i, GetFlexWeight( i ) * 0.95 );
  748. }
  749. bool bHasForegroundEvents = false;
  750. // Iterate SceneEvents and look for active slots
  751. for ( int i = 0; i < m_SceneEvents.Count(); i++ )
  752. {
  753. CSceneEventInfo *info = &m_SceneEvents[ i ];
  754. Assert( info );
  755. // FIXME: Need a safe handle to m_pEvent in case of memory deletion?
  756. CChoreoEvent *event = info->m_pEvent;
  757. Assert( event );
  758. CChoreoScene *scene = info->m_pScene;
  759. Assert( scene );
  760. if ( scene && !scene->IsBackground() )
  761. {
  762. bHasForegroundEvents = true;
  763. }
  764. if (ProcessSceneEvent( info, scene, event ))
  765. {
  766. info->m_bStarted = true;
  767. }
  768. }
  769. if ( bHasForegroundEvents && scene_showunlock.GetBool())
  770. {
  771. CAI_BaseNPC *myNpc = MyNPCPointer( );
  772. if ( myNpc && !(myNpc->GetState() == NPC_STATE_SCRIPT || myNpc->IsCurSchedule( SCHED_SCENE_GENERIC )) )
  773. {
  774. Vector p0 = myNpc->GetHullMins();
  775. Vector p1 = myNpc->GetHullMaxs();
  776. p0.z = p1.z + 2;
  777. p1.z = p1.z + 2;
  778. NDebugOverlay::Box( myNpc->GetAbsOrigin(), p0, p1, 255, 0, 0, 0, 0.12 );
  779. }
  780. }
  781. // any needed layer priorites have now been reset
  782. m_bUpdateLayerPriorities = false;
  783. }
  784. class CFlexSceneFileManager : CAutoGameSystem
  785. {
  786. public:
  787. CFlexSceneFileManager( char const *name ) : CAutoGameSystem( name )
  788. {
  789. }
  790. virtual bool Init()
  791. {
  792. // Trakcer 16692: Preload these at startup to avoid hitch first time we try to load them during actual gameplay
  793. FindSceneFile( NULL, "phonemes", true );
  794. FindSceneFile( NULL, "phonemes_weak", true );
  795. FindSceneFile( NULL, "phonemes_strong", true );
  796. #if defined( HL2_DLL )
  797. FindSceneFile( NULL, "random", true );
  798. FindSceneFile( NULL, "randomAlert", true );
  799. #endif
  800. return true;
  801. }
  802. // Tracker 14992: We used to load 18K of .vfes for every CBaseFlex who lipsynced, but now we only load those files once globally.
  803. // Note, we could wipe these between levels, but they don't ever load more than the weak/normal/strong phoneme classes that I can tell
  804. // so I'll just leave them loaded forever for now
  805. virtual void Shutdown()
  806. {
  807. DeleteSceneFiles();
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Purpose: Sets up translations
  811. // Input : *instance -
  812. // *pSettinghdr -
  813. // Output : void
  814. //-----------------------------------------------------------------------------
  815. void EnsureTranslations( CBaseFlex *instance, const flexsettinghdr_t *pSettinghdr )
  816. {
  817. // The only time instance is NULL is in Init() above, where we're just loading the .vfe files off of the hard disk.
  818. if ( instance )
  819. {
  820. instance->EnsureTranslations( pSettinghdr );
  821. }
  822. }
  823. const void *FindSceneFile( CBaseFlex *instance, const char *filename, bool allowBlockingIO )
  824. {
  825. // See if it's already loaded
  826. int i;
  827. for ( i = 0; i < m_FileList.Size(); i++ )
  828. {
  829. CFlexSceneFile *file = m_FileList[ i ];
  830. if ( file && !stricmp( file->filename, filename ) )
  831. {
  832. // Make sure translations (local to global flex controller) are set up for this instance
  833. EnsureTranslations( instance, ( const flexsettinghdr_t * )file->buffer );
  834. return file->buffer;
  835. }
  836. }
  837. if ( !allowBlockingIO )
  838. {
  839. return NULL;
  840. }
  841. // Load file into memory
  842. void *buffer = NULL;
  843. int len = filesystem->ReadFileEx( UTIL_VarArgs( "expressions/%s.vfe", filename ), "GAME", &buffer, false, true );
  844. if ( !len )
  845. return NULL;
  846. // Create scene entry
  847. CFlexSceneFile *pfile = new CFlexSceneFile;
  848. // Remember filename
  849. Q_strncpy( pfile->filename, filename, sizeof( pfile->filename ) );
  850. // Remember data pointer
  851. pfile->buffer = buffer;
  852. // Add to list
  853. m_FileList.AddToTail( pfile );
  854. // Swap the entire file
  855. if ( IsX360() )
  856. {
  857. CByteswap swap;
  858. swap.ActivateByteSwapping( true );
  859. byte *pData = (byte*)buffer;
  860. flexsettinghdr_t *pHdr = (flexsettinghdr_t*)pData;
  861. swap.SwapFieldsToTargetEndian( pHdr );
  862. // Flex Settings
  863. flexsetting_t *pFlexSetting = (flexsetting_t*)((byte*)pHdr + pHdr->flexsettingindex);
  864. for ( int i = 0; i < pHdr->numflexsettings; ++i, ++pFlexSetting )
  865. {
  866. swap.SwapFieldsToTargetEndian( pFlexSetting );
  867. flexweight_t *pWeight = (flexweight_t*)(((byte*)pFlexSetting) + pFlexSetting->settingindex );
  868. for ( int j = 0; j < pFlexSetting->numsettings; ++j, ++pWeight )
  869. {
  870. swap.SwapFieldsToTargetEndian( pWeight );
  871. }
  872. }
  873. // indexes
  874. pData = (byte*)pHdr + pHdr->indexindex;
  875. swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numindexes );
  876. // keymappings
  877. pData = (byte*)pHdr + pHdr->keymappingindex;
  878. swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys );
  879. // keyname indices
  880. pData = (byte*)pHdr + pHdr->keynameindex;
  881. swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys );
  882. }
  883. // Fill in translation table
  884. EnsureTranslations( instance, ( const flexsettinghdr_t * )pfile->buffer );
  885. // Return data
  886. return pfile->buffer;
  887. }
  888. private:
  889. void DeleteSceneFiles()
  890. {
  891. while ( m_FileList.Size() > 0 )
  892. {
  893. CFlexSceneFile *file = m_FileList[ 0 ];
  894. m_FileList.Remove( 0 );
  895. filesystem->FreeOptimalReadBuffer( file->buffer );
  896. delete file;
  897. }
  898. }
  899. CUtlVector< CFlexSceneFile * > m_FileList;
  900. };
  901. // Singleton manager
  902. CFlexSceneFileManager g_FlexSceneFileManager( "CFlexSceneFileManager" );
  903. //-----------------------------------------------------------------------------
  904. // Purpose: Each CBaseFlex maintains a UtlRBTree of mappings, one for each loaded flex scene file it uses. This is used to
  905. // sort the entries in the RBTree
  906. // Input : lhs -
  907. // rhs -
  908. // Output : Returns true on success, false on failure.
  909. //-----------------------------------------------------------------------------
  910. bool CBaseFlex::FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs )
  911. {
  912. return lhs.m_Key < rhs.m_Key;
  913. }
  914. //-----------------------------------------------------------------------------
  915. // Purpose: Since everyone shared a pSettinghdr now, we need to set up the localtoglobal mapping per entity, but
  916. // we just do this in memory with an array of integers (could be shorts, I suppose)
  917. // Input : *pSettinghdr -
  918. //-----------------------------------------------------------------------------
  919. void CBaseFlex::EnsureTranslations( const flexsettinghdr_t *pSettinghdr )
  920. {
  921. Assert( pSettinghdr );
  922. FS_LocalToGlobal_t entry( pSettinghdr );
  923. unsigned short idx = m_LocalToGlobal.Find( entry );
  924. if ( idx != m_LocalToGlobal.InvalidIndex() )
  925. return;
  926. entry.SetCount( pSettinghdr->numkeys );
  927. for ( int i = 0; i < pSettinghdr->numkeys; ++i )
  928. {
  929. entry.m_Mapping[ i ] = FindFlexController( pSettinghdr->pLocalName( i ) );
  930. }
  931. m_LocalToGlobal.Insert( entry );
  932. }
  933. //-----------------------------------------------------------------------------
  934. // Purpose: Look up instance specific mapping
  935. // Input : *pSettinghdr -
  936. // key -
  937. // Output : int
  938. //-----------------------------------------------------------------------------
  939. LocalFlexController_t CBaseFlex::FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key )
  940. {
  941. FS_LocalToGlobal_t entry( pSettinghdr );
  942. int idx = m_LocalToGlobal.Find( entry );
  943. if ( idx == m_LocalToGlobal.InvalidIndex() )
  944. {
  945. // This should never happen!!!
  946. Assert( 0 );
  947. Warning( "Unable to find mapping for flexcontroller %i, settings %p on %i/%s\n", key, pSettinghdr, entindex(), GetClassname() );
  948. EnsureTranslations( pSettinghdr );
  949. idx = m_LocalToGlobal.Find( entry );
  950. if ( idx == m_LocalToGlobal.InvalidIndex() )
  951. {
  952. Error( "CBaseFlex::FlexControllerLocalToGlobal failed!\n" );
  953. }
  954. }
  955. FS_LocalToGlobal_t& result = m_LocalToGlobal[ idx ];
  956. // Validate lookup
  957. Assert( result.m_nCount != 0 && key < result.m_nCount );
  958. LocalFlexController_t index = result.m_Mapping[ key ];
  959. return index;
  960. }
  961. //-----------------------------------------------------------------------------
  962. // Purpose:
  963. // Input : *filename -
  964. //-----------------------------------------------------------------------------
  965. const void *CBaseFlex::FindSceneFile( const char *filename )
  966. {
  967. // Ask manager to get the globally cached scene instead.
  968. return g_FlexSceneFileManager.FindSceneFile( this, filename, false );
  969. }
  970. ConVar ai_expression_optimization( "ai_expression_optimization", "0", FCVAR_NONE, "Disable npc background expressions when you can't see them." );
  971. ConVar ai_expression_frametime( "ai_expression_frametime", "0.05", FCVAR_NONE, "Maximum frametime to still play background expressions." );
  972. //-----------------------------------------------------------------------------
  973. // Various methods to process facial SceneEvents:
  974. //-----------------------------------------------------------------------------
  975. bool CBaseFlex::ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  976. {
  977. VPROF( "CBaseFlex::ProcessFlexAnimationSceneEvent" );
  978. if ( event->HasEndTime() )
  979. {
  980. // don't bother with flex animation if the player can't see you
  981. CAI_BaseNPC *myNpc = MyNPCPointer( );
  982. if (myNpc)
  983. {
  984. if (!myNpc->HasCondition( COND_IN_PVS ))
  985. return true;
  986. if (ai_expression_optimization.GetBool())
  987. {
  988. if (scene->IsBackground())
  989. {
  990. // if framerate too slow, disable
  991. if (gpGlobals->frametime > ai_expression_frametime.GetFloat())
  992. {
  993. info->m_bHasArrived = true;
  994. info->m_flNext = gpGlobals->curtime + RandomFloat( 0.7, 1.2 );
  995. }
  996. // only check occasionally
  997. else if (info->m_flNext <= gpGlobals->curtime)
  998. {
  999. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  1000. // if not in view, disable
  1001. info->m_bHasArrived = (pPlayer && !pPlayer->FInViewCone( this ) );
  1002. info->m_flNext = gpGlobals->curtime + RandomFloat( 0.7, 1.2 );
  1003. }
  1004. if (info->m_bHasArrived)
  1005. {
  1006. // NDebugOverlay::Box( myNpc->GetAbsOrigin(), myNpc->GetHullMins(), myNpc->GetHullMaxs(), 255, 0, 0, 0, 0.22 );
  1007. return true;
  1008. }
  1009. // NDebugOverlay::Box( myNpc->GetAbsOrigin(), myNpc->GetHullMins(), myNpc->GetHullMaxs(), 0, 255, 0, 0, 0.22 );
  1010. }
  1011. }
  1012. }
  1013. AddFlexAnimation( info );
  1014. }
  1015. return true;
  1016. }
  1017. bool CBaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1018. {
  1019. // Flexanimations have to have an end time!!!
  1020. if ( !event->HasEndTime() )
  1021. return true;
  1022. VPROF( "CBaseFlex::ProcessFlexSettingSceneEvent" );
  1023. // Look up the actual strings
  1024. const char *scenefile = event->GetParameters();
  1025. const char *name = event->GetParameters2();
  1026. // Have to find both strings
  1027. if ( scenefile && name )
  1028. {
  1029. // Find the scene file
  1030. const flexsettinghdr_t *pExpHdr = ( const flexsettinghdr_t * )FindSceneFile( scenefile );
  1031. if ( pExpHdr )
  1032. {
  1033. float scenetime = scene->GetTime();
  1034. float scale = event->GetIntensity( scenetime );
  1035. // Add the named expression
  1036. AddFlexSetting( name, scale, pExpHdr, !info->m_bStarted );
  1037. }
  1038. }
  1039. return true;
  1040. }
  1041. bool CBaseFlex::ProcessFacingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1042. {
  1043. // make sure target exists
  1044. if (info->m_hTarget == NULL)
  1045. return false;
  1046. VPROF( "CBaseFlex::ProcessFacingSceneEvent" );
  1047. // make sure we're still able to play this command
  1048. if (!EnterSceneSequence( scene, event, true ))
  1049. {
  1050. return false;
  1051. }
  1052. if (!info->m_bStarted)
  1053. {
  1054. info->m_flInitialYaw = GetLocalAngles().y;
  1055. }
  1056. // lock in place if aiming at self
  1057. if (info->m_hTarget == this)
  1058. {
  1059. return true;
  1060. }
  1061. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1062. if (myNpc)
  1063. {
  1064. if (info->m_bIsMoving != IsMoving())
  1065. {
  1066. info->m_flInitialYaw = GetLocalAngles().y;
  1067. }
  1068. info->m_bIsMoving = IsMoving();
  1069. // Msg("%f : %f - %f\n", scene->GetTime(), event->GetStartTime(), event->GetEndTime() );
  1070. // FIXME: why are the splines ill behaved at the end?
  1071. float intensity = event->GetIntensity( scene->GetTime() );
  1072. if (info->m_bIsMoving)
  1073. {
  1074. myNpc->AddFacingTarget( info->m_hTarget, intensity, 0.2 );
  1075. }
  1076. else
  1077. {
  1078. float goalYaw = myNpc->CalcIdealYaw( info->m_hTarget->EyePosition() );
  1079. float diff = UTIL_AngleDiff( goalYaw, info->m_flInitialYaw );
  1080. float idealYaw = UTIL_AngleMod( info->m_flInitialYaw + diff * intensity );
  1081. // Msg("yaw %.1f : %.1f (%.1f)\n", info->m_flInitialYaw, idealYaw, intensity );
  1082. myNpc->GetMotor()->SetIdealYawAndUpdate( idealYaw );
  1083. }
  1084. return true;
  1085. }
  1086. return false;
  1087. }
  1088. static Activity DetermineExpressionMoveActivity( CChoreoEvent *event, CAI_BaseNPC *pNPC )
  1089. {
  1090. Activity activity = ACT_WALK;
  1091. const char *sParam2 = event->GetParameters2();
  1092. if ( !sParam2 || !sParam2[0] )
  1093. return activity;
  1094. // Custom distance styles are appended to param2 with a space as a separator
  1095. const char *pszAct = Q_strstr( sParam2, " " );
  1096. char szActName[256];
  1097. if ( pszAct )
  1098. {
  1099. Q_strncpy( szActName, sParam2, sizeof(szActName) );
  1100. szActName[ (pszAct-sParam2) ] = '\0';
  1101. pszAct = szActName;
  1102. }
  1103. else
  1104. {
  1105. pszAct = sParam2;
  1106. }
  1107. if ( !Q_stricmp( pszAct, "Walk" ) )
  1108. {
  1109. activity = ACT_WALK;
  1110. }
  1111. else if ( !Q_stricmp( pszAct, "Run" ) )
  1112. {
  1113. activity = ACT_RUN;
  1114. }
  1115. else if ( !Q_stricmp( pszAct, "CrouchWalk" ) )
  1116. {
  1117. activity = ACT_WALK_CROUCH;
  1118. }
  1119. else
  1120. {
  1121. // Try and resolve the activity name
  1122. activity = (Activity)ActivityList_IndexForName( pszAct );
  1123. if ( activity == ACT_INVALID )
  1124. {
  1125. // Assume it's a sequence name
  1126. pNPC->m_iszSceneCustomMoveSeq = AllocPooledString( pszAct );
  1127. activity = ACT_SCRIPT_CUSTOM_MOVE;
  1128. }
  1129. }
  1130. return activity;
  1131. }
  1132. bool CBaseFlex::ProcessMoveToSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1133. {
  1134. // make sure target exists
  1135. if (info->m_hTarget == NULL)
  1136. return false;
  1137. // FIXME: move to CBaseActor or BaseNPC
  1138. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1139. if (!myNpc)
  1140. return false;
  1141. VPROF( "CBaseFlex::ProcessMoveToSceneEvent" );
  1142. // make sure we're still able to play this command
  1143. if (!EnterSceneSequence( scene, event, true ))
  1144. {
  1145. return false;
  1146. }
  1147. // lock in place if aiming at self
  1148. if (info->m_hTarget == this)
  1149. {
  1150. return true;
  1151. }
  1152. // If we're in a vehicle, make us exit and *then* begin the run
  1153. if ( myNpc->IsInAVehicle() )
  1154. {
  1155. // Make us exit and wait
  1156. myNpc->ExitVehicle();
  1157. return false;
  1158. }
  1159. const Task_t *pCurTask = myNpc->GetTask();
  1160. if (!info->m_bIsMoving && (!IsMoving() || pCurTask->iTask == TASK_STOP_MOVING) )
  1161. {
  1162. if ( pCurTask && (pCurTask->iTask == TASK_PLAY_SCENE || pCurTask->iTask == TASK_WAIT_FOR_MOVEMENT || pCurTask->iTask == TASK_STOP_MOVING ) )
  1163. {
  1164. Activity moveActivity = DetermineExpressionMoveActivity( event, myNpc );
  1165. // AI_NavGoal_t goal( info->m_hTarget->EyePosition(), moveActivity, AIN_HULL_TOLERANCE );
  1166. myNpc->SetTarget( info->m_hTarget );
  1167. float flDistTolerance;
  1168. flDistTolerance = myNpc->GetHullWidth() / 2.0;
  1169. // flDistTolerance = AIN_HULL_TOLERANCE;
  1170. if (event->m_bForceShortMovement)
  1171. {
  1172. flDistTolerance = 0.1f;
  1173. }
  1174. AI_NavGoal_t goal( GOALTYPE_TARGETENT, moveActivity, flDistTolerance, AIN_UPDATE_TARGET_POS );
  1175. float flDist = (info->m_hTarget->EyePosition() - GetAbsOrigin()).Length2D();
  1176. if (flDist > MAX( MAX( flDistTolerance, 0.1 ), event->GetDistanceToTarget()))
  1177. {
  1178. // Msg("flDist %.1f\n", flDist );
  1179. int result = false;
  1180. if ( !myNpc->IsUnreachable( info->m_hTarget ) )
  1181. {
  1182. result = myNpc->GetNavigator()->SetGoal( goal, AIN_CLEAR_TARGET );
  1183. if ( !result )
  1184. {
  1185. myNpc->RememberUnreachable( info->m_hTarget, 1.5 );
  1186. }
  1187. }
  1188. if (result)
  1189. {
  1190. myNpc->GetNavigator()->SetMovementActivity( moveActivity );
  1191. myNpc->GetNavigator()->SetArrivalDistance( event->GetDistanceToTarget() );
  1192. info->m_bIsMoving = true;
  1193. }
  1194. else
  1195. {
  1196. // need route build failure case
  1197. // Msg("actor %s unable to build route\n", STRING( myNpc->GetEntityName() ) );
  1198. // Assert(0);
  1199. if (developer.GetInt() > 0 && scene_showmoveto.GetBool())
  1200. {
  1201. Vector vTestPoint;
  1202. myNpc->GetMoveProbe()->FloorPoint( info->m_hTarget->EyePosition(), MASK_NPCSOLID, 0, -64, &vTestPoint );
  1203. NDebugOverlay::HorzArrow( GetAbsOrigin() + Vector( 0, 0, 1 ), vTestPoint + Vector( 0, 0, 1 ), 4, 255, 0, 255, 0, false, 0.12 );
  1204. NDebugOverlay::Box( vTestPoint, myNpc->GetHullMins(), myNpc->GetHullMaxs(), 255, 0, 255, 0, 0.12 );
  1205. }
  1206. }
  1207. }
  1208. else
  1209. {
  1210. info->m_bHasArrived = true;
  1211. }
  1212. }
  1213. }
  1214. else if (IsMoving())
  1215. {
  1216. // float flDist = (myNpc->GetNavigator()->GetGoalPos() - GetAbsOrigin()).Length2D();
  1217. float flDist = (info->m_hTarget->EyePosition() - GetAbsOrigin()).Length2D();
  1218. if (flDist <= event->GetDistanceToTarget())
  1219. {
  1220. myNpc->GetNavigator()->StopMoving( false ); // Stop moving
  1221. info->m_bHasArrived = true;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. info->m_bIsMoving = false;
  1227. }
  1228. // show movement target
  1229. if (developer.GetInt() > 0 && scene_showmoveto.GetBool() && IsMoving())
  1230. {
  1231. Vector vecStart, vTestPoint;
  1232. vecStart = myNpc->GetNavigator()->GetGoalPos();
  1233. myNpc->GetMoveProbe()->FloorPoint( vecStart, MASK_NPCSOLID, 0, -64, &vTestPoint );
  1234. int r, g, b;
  1235. r = b = g = 0;
  1236. if ( myNpc->GetNavigator()->CanFitAtPosition( vTestPoint, MASK_NPCSOLID ) )
  1237. {
  1238. if ( myNpc->GetMoveProbe()->CheckStandPosition( vTestPoint, MASK_NPCSOLID ) )
  1239. {
  1240. if (event->IsResumeCondition())
  1241. {
  1242. g = 255;
  1243. }
  1244. else
  1245. {
  1246. r = 255; g = 255;
  1247. }
  1248. }
  1249. else
  1250. {
  1251. b = 255; g = 255;
  1252. }
  1253. }
  1254. else
  1255. {
  1256. r = 255;
  1257. }
  1258. NDebugOverlay::HorzArrow( GetAbsOrigin() + Vector( 0, 0, 1 ), vTestPoint + Vector( 0, 0, 1 ), 4, r, g, b, 0, false, 0.12 );
  1259. NDebugOverlay::Box( vTestPoint, myNpc->GetHullMins(), myNpc->GetHullMaxs(), r, g, b, 0, 0.12 );
  1260. }
  1261. // handled in task
  1262. return true;
  1263. }
  1264. bool CBaseFlex::ProcessLookAtSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1265. {
  1266. VPROF( "CBaseFlex::ProcessLookAtSceneEvent" );
  1267. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1268. if (myNpc && info->m_hTarget != NULL)
  1269. {
  1270. float intensity = event->GetIntensity( scene->GetTime() );
  1271. // clamp in-ramp to 0.3 seconds
  1272. float flDuration = scene->GetTime() - event->GetStartTime();
  1273. float flMaxIntensity = flDuration < 0.3f ? SimpleSpline( flDuration / 0.3f ) : 1.0f;
  1274. intensity = clamp( intensity, 0.0f, flMaxIntensity );
  1275. myNpc->AddLookTarget( info->m_hTarget, intensity, 0.1 );
  1276. if (developer.GetInt() > 0 && scene_showlook.GetBool() && info->m_hTarget)
  1277. {
  1278. Vector tmp = info->m_hTarget->EyePosition() - myNpc->EyePosition();
  1279. VectorNormalize( tmp );
  1280. Vector p0 = myNpc->EyePosition();
  1281. NDebugOverlay::VertArrow( p0, p0 + tmp * (4 + 16 * intensity ), 4, 255, 255, 255, 0, true, 0.12 );
  1282. }
  1283. }
  1284. return true;
  1285. }
  1286. //-----------------------------------------------------------------------------
  1287. // Purpose:
  1288. //-----------------------------------------------------------------------------
  1289. bool CBaseFlex::ProcessSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1290. {
  1291. VPROF( "CBaseFlex::ProcessSceneEvent" );
  1292. switch ( event->GetType() )
  1293. {
  1294. case CChoreoEvent::FLEXANIMATION:
  1295. return ProcessFlexAnimationSceneEvent( info, scene, event );
  1296. case CChoreoEvent::EXPRESSION:
  1297. return ProcessFlexSettingSceneEvent( info, scene, event );
  1298. case CChoreoEvent::SEQUENCE:
  1299. return ProcessSequenceSceneEvent( info, scene, event );
  1300. case CChoreoEvent::GESTURE:
  1301. return ProcessGestureSceneEvent( info, scene, event );
  1302. case CChoreoEvent::FACE:
  1303. return ProcessFacingSceneEvent( info, scene, event );
  1304. case CChoreoEvent::MOVETO:
  1305. return ProcessMoveToSceneEvent( info, scene, event );
  1306. case CChoreoEvent::LOOKAT:
  1307. return ProcessLookAtSceneEvent( info, scene, event );
  1308. case CChoreoEvent::SPEAK:
  1309. return true;
  1310. default:
  1311. {
  1312. Msg( "unknown type %d in ProcessSceneEvent()\n", event->GetType() );
  1313. Assert( 0 );
  1314. }
  1315. }
  1316. return false;
  1317. }
  1318. //-----------------------------------------------------------------------------
  1319. // Purpose:
  1320. //-----------------------------------------------------------------------------
  1321. bool CBaseFlex::IsRunningSceneMoveToEvent()
  1322. {
  1323. for ( int i = m_SceneEvents.Count() - 1; i >= 0; i-- )
  1324. {
  1325. CSceneEventInfo *info = &m_SceneEvents[ i ];
  1326. CChoreoEvent *event = info->m_pEvent;
  1327. if ( event && event->GetType() == CChoreoEvent::MOVETO )
  1328. return true;
  1329. }
  1330. return false;
  1331. }
  1332. flexsetting_t const *CBaseFlex::FindNamedSetting( flexsettinghdr_t const *pSettinghdr, const char *expr )
  1333. {
  1334. int i;
  1335. const flexsetting_t *pSetting = NULL;
  1336. for ( i = 0; i < pSettinghdr->numflexsettings; i++ )
  1337. {
  1338. pSetting = pSettinghdr->pSetting( i );
  1339. if ( !pSetting )
  1340. continue;
  1341. const char *name = pSetting->pszName();
  1342. if ( !stricmp( name, expr ) )
  1343. break;
  1344. }
  1345. if ( i>=pSettinghdr->numflexsettings )
  1346. {
  1347. return NULL;
  1348. }
  1349. return pSetting;
  1350. }
  1351. //-----------------------------------------------------------------------------
  1352. // Purpose:
  1353. // Input : *event -
  1354. //-----------------------------------------------------------------------------
  1355. void CBaseFlex::AddFlexAnimation( CSceneEventInfo *info )
  1356. {
  1357. if ( !info )
  1358. return;
  1359. // don't bother with flex animation if the player can't see you
  1360. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1361. if (myNpc && !myNpc->HasCondition( COND_IN_PVS ))
  1362. return;
  1363. CChoreoEvent *event = info->m_pEvent;
  1364. if ( !event )
  1365. return;
  1366. CChoreoScene *scene = info->m_pScene;
  1367. if ( !scene )
  1368. return;
  1369. if ( !event->GetTrackLookupSet() )
  1370. {
  1371. // Create lookup data
  1372. for ( int i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
  1373. {
  1374. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  1375. if ( !track )
  1376. continue;
  1377. if ( track->IsComboType() )
  1378. {
  1379. char name[ 512 ];
  1380. Q_strncpy( name, "right_" ,sizeof(name));
  1381. Q_strncat( name, track->GetFlexControllerName(),sizeof(name), COPY_ALL_CHARACTERS );
  1382. track->SetFlexControllerIndex( FindFlexController( name ), 0, 0 );
  1383. if ( CAI_BaseActor::IsServerSideFlexController( name ) )
  1384. {
  1385. Assert( !"Should stereo controllers ever be server side only?" );
  1386. track->SetServerSide( true );
  1387. }
  1388. Q_strncpy( name, "left_" ,sizeof(name));
  1389. Q_strncat( name, track->GetFlexControllerName(),sizeof(name), COPY_ALL_CHARACTERS );
  1390. track->SetFlexControllerIndex( FindFlexController( name ), 0, 1 );
  1391. if ( CAI_BaseActor::IsServerSideFlexController( name ) )
  1392. {
  1393. Assert( !"Should stereo controllers ever be server side only?" );
  1394. track->SetServerSide( true );
  1395. }
  1396. }
  1397. else
  1398. {
  1399. track->SetFlexControllerIndex( FindFlexController( (char *)track->GetFlexControllerName() ), 0 );
  1400. // Only non-combo tracks can be server side
  1401. track->SetServerSide( CAI_BaseActor::IsServerSideFlexController( track->GetFlexControllerName() ) );
  1402. }
  1403. }
  1404. event->SetTrackLookupSet( true );
  1405. }
  1406. float scenetime = scene->GetTime();
  1407. // decay if this is a background scene and there's other flex animations playing
  1408. float weight = event->GetIntensity( scenetime ) * info->UpdateWeight( this );
  1409. {
  1410. VPROF( "AddFlexAnimation_SetFlexWeight" );
  1411. // Compute intensity for each track in animation and apply
  1412. // Iterate animation tracks
  1413. for ( int i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
  1414. {
  1415. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  1416. if ( !track )
  1417. continue;
  1418. // Disabled
  1419. if ( !track->IsTrackActive() )
  1420. continue;
  1421. // If we are doing client side flexing, skip all tracks which are not server side
  1422. if ( g_bClientFlex && !track->IsServerSide() )
  1423. continue;
  1424. // Map track flex controller to global name
  1425. if ( track->IsComboType() )
  1426. {
  1427. for ( int side = 0; side < 2; side++ )
  1428. {
  1429. LocalFlexController_t controller = track->GetRawFlexControllerIndex( side );
  1430. // Get spline intensity for controller
  1431. float flIntensity = track->GetIntensity( scenetime, side );
  1432. if ( controller >= LocalFlexController_t(0) )
  1433. {
  1434. float orig = GetFlexWeight( controller );
  1435. SetFlexWeight( controller, orig * (1 - weight) + flIntensity * weight );
  1436. }
  1437. }
  1438. }
  1439. else
  1440. {
  1441. LocalFlexController_t controller = track->GetRawFlexControllerIndex( 0 );
  1442. // Get spline intensity for controller
  1443. float flIntensity = track->GetIntensity( scenetime, 0 );
  1444. if ( controller >= LocalFlexController_t(0) )
  1445. {
  1446. float orig = GetFlexWeight( controller );
  1447. SetFlexWeight( controller, orig * (1 - weight) + flIntensity * weight );
  1448. }
  1449. }
  1450. }
  1451. }
  1452. info->m_bStarted = true;
  1453. }
  1454. //-----------------------------------------------------------------------------
  1455. // Purpose:
  1456. // Input : *expr -
  1457. // scale -
  1458. // *pSettinghdr -
  1459. // newexpression -
  1460. //-----------------------------------------------------------------------------
  1461. void CBaseFlex::AddFlexSetting( const char *expr, float scale,
  1462. const flexsettinghdr_t *pSettinghdr, bool newexpression )
  1463. {
  1464. int i;
  1465. const flexsetting_t *pSetting = NULL;
  1466. // Find the named setting in the base
  1467. for ( i = 0; i < pSettinghdr->numflexsettings; i++ )
  1468. {
  1469. pSetting = pSettinghdr->pSetting( i );
  1470. if ( !pSetting )
  1471. continue;
  1472. const char *name = pSetting->pszName();
  1473. if ( !stricmp( name, expr ) )
  1474. break;
  1475. }
  1476. if ( i>=pSettinghdr->numflexsettings )
  1477. {
  1478. return;
  1479. }
  1480. flexweight_t *pWeights = NULL;
  1481. int truecount = pSetting->psetting( (byte *)pSettinghdr, 0, &pWeights );
  1482. if ( !pWeights )
  1483. return;
  1484. for (i = 0; i < truecount; i++, pWeights++)
  1485. {
  1486. // Translate to local flex controller
  1487. // this is translating from the settings's local index to the models local index
  1488. LocalFlexController_t index = FlexControllerLocalToGlobal( pSettinghdr, pWeights->key );
  1489. // blend scaled weighting in to total
  1490. float s = clamp( scale * pWeights->influence, 0.0f, 1.0f );
  1491. float value = GetFlexWeight( index ) * (1.0f - s ) + pWeights->weight * s;
  1492. SetFlexWeight( index, value );
  1493. }
  1494. }
  1495. //-----------------------------------------------------------------------------
  1496. // Purpose:
  1497. // Input : *actor -
  1498. // *parameters -
  1499. //-----------------------------------------------------------------------------
  1500. bool CBaseFlex::ProcessGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1501. {
  1502. if ( !info || !event || !scene )
  1503. return false;
  1504. if ( info->m_iLayer == REQUEST_DEFERRED_LAYER_ALLOCATION )
  1505. {
  1506. HandleStartGestureSceneEvent( info, scene, event, info->m_pActor );
  1507. }
  1508. if (info->m_iLayer >= 0)
  1509. {
  1510. // this happens after StudioFrameAdvance()
  1511. // FIXME; this needs to be adjusted by npc offset to scene time? Known?
  1512. // FIXME: what should this do when the scene loops?
  1513. float duration = event->GetDuration( );
  1514. float flEventCycle = (scene->GetTime() - event->GetStartTime()) / duration;
  1515. float flCycle = event->GetOriginalPercentageFromPlaybackPercentage( flEventCycle );
  1516. SetLayerCycle( info->m_iLayer, flCycle );
  1517. float flWeight = event->GetIntensity( scene->GetTime() );
  1518. /*
  1519. if (stricmp( event->GetParameters(), "m_g_arms_crossed" ) == 0)
  1520. {
  1521. Msg("%.2f (%.2f) : %s : %.3f (%.3f) %.2f\n", scene->GetTime(), scene->GetTime() - event->GetStartTime(), event->GetParameters(), flCycle, flEventCycle, flWeight );
  1522. }
  1523. */
  1524. // fade out/in if npc is moving
  1525. if (!info->m_bIsGesture)
  1526. {
  1527. if (IsMoving())
  1528. {
  1529. info->m_flWeight = MAX( info->m_flWeight - 0.2, 0.0 );
  1530. }
  1531. else
  1532. {
  1533. info->m_flWeight = MIN( info->m_flWeight + 0.2, 1.0 );
  1534. }
  1535. }
  1536. // 3x^2-2x^3
  1537. float spline = 3 * info->m_flWeight * info->m_flWeight - 2 * info->m_flWeight * info->m_flWeight * info->m_flWeight;
  1538. SetLayerWeight( info->m_iLayer, flWeight * spline );
  1539. // update layer priority
  1540. if (m_bUpdateLayerPriorities)
  1541. {
  1542. SetLayerPriority( info->m_iLayer, info->m_iPriority + GetScenePriority( scene ) );
  1543. }
  1544. /*
  1545. Msg( "%d : %.2f (%.2f) : %.3f %.3f : %.3f\n",
  1546. info->m_iLayer,
  1547. scene->GetTime(),
  1548. (scene->GetTime() - event->GetStartTime()) / duration,
  1549. flCycle,
  1550. flNextCycle,
  1551. rate );
  1552. */
  1553. }
  1554. return true;
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // Purpose:
  1558. // Input : *actor -
  1559. // *parameters -
  1560. //-----------------------------------------------------------------------------
  1561. bool CBaseFlex::ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event )
  1562. {
  1563. if ( !info || !event || !scene )
  1564. return false;
  1565. bool bNewlyAllocated = false;
  1566. if ( info->m_iLayer == REQUEST_DEFERRED_LAYER_ALLOCATION )
  1567. {
  1568. bool result = HandleStartSequenceSceneEvent( info, scene, event, info->m_pActor );
  1569. if (!result)
  1570. return false;
  1571. bNewlyAllocated = true;
  1572. }
  1573. if (info->m_iLayer >= 0)
  1574. {
  1575. float flWeight = event->GetIntensity( scene->GetTime() );
  1576. // force layer to zero weight in newly allocated, fixed bug with inter-think spawned sequences blending in badly
  1577. if (bNewlyAllocated)
  1578. flWeight = 0.0;
  1579. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1580. // fade out/in if npc is moving
  1581. bool bFadeOut = IsMoving();
  1582. if (myNpc && !(myNpc->IsCurSchedule( SCHED_SCENE_GENERIC ) || myNpc->GetActivity() == ACT_IDLE_ANGRY || myNpc->GetActivity() == ACT_IDLE) )
  1583. {
  1584. bFadeOut = true;
  1585. if (info->m_flWeight == 1.0)
  1586. {
  1587. Warning( "%s playing CChoreoEvent::SEQUENCE but AI has forced them to do something different\n", STRING(GetEntityName()) );
  1588. }
  1589. }
  1590. if (bFadeOut)
  1591. {
  1592. info->m_flWeight = MAX( info->m_flWeight - 0.2, 0.0 );
  1593. }
  1594. else
  1595. {
  1596. info->m_flWeight = MIN( info->m_flWeight + 0.2, 1.0 );
  1597. }
  1598. float spline = 3 * info->m_flWeight * info->m_flWeight - 2 * info->m_flWeight * info->m_flWeight * info->m_flWeight;
  1599. SetLayerWeight( info->m_iLayer, flWeight * spline );
  1600. bool looping = ((GetSequenceFlags( GetModelPtr(), info->m_nSequence ) & STUDIO_LOOPING) != 0);
  1601. if (!looping)
  1602. {
  1603. float dt = scene->GetTime() - event->GetStartTime();
  1604. float seq_duration = SequenceDuration( info->m_nSequence );
  1605. float flCycle = dt / seq_duration;
  1606. flCycle = clamp( flCycle, 0.f, 1.0f );
  1607. SetLayerCycle( info->m_iLayer, flCycle );
  1608. }
  1609. if (myNpc)
  1610. {
  1611. myNpc->AddSceneLock( 0.2 );
  1612. }
  1613. // update layer priority
  1614. if (m_bUpdateLayerPriorities)
  1615. {
  1616. SetLayerPriority( info->m_iLayer, info->m_iPriority + GetScenePriority( scene ) );
  1617. }
  1618. }
  1619. // FIXME: clean up cycle index from restart
  1620. return true;
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose: Returns true if the actor is not currently in a scene OR if the actor
  1624. // is in a scene (checked externally), but a PERMIT_RESPONSES event is active and
  1625. // the permit time period has enough time remaining to handle the response in full.
  1626. // Input : response_length -
  1627. //-----------------------------------------------------------------------------
  1628. bool CBaseFlex::PermitResponse( float response_length )
  1629. {
  1630. // Nothing set, disallow it
  1631. if ( m_flAllowResponsesEndTime <= 0.0f )
  1632. {
  1633. return false;
  1634. }
  1635. // If response ends before end of allow time, then that's okay
  1636. if ( gpGlobals->curtime + response_length <= m_flAllowResponsesEndTime )
  1637. {
  1638. return true;
  1639. }
  1640. // Disallow responses for now
  1641. return false;
  1642. }
  1643. //-----------------------------------------------------------------------------
  1644. // Purpose: Set response end time (0 to clear response blocking)
  1645. // Input : endtime -
  1646. //-----------------------------------------------------------------------------
  1647. void CBaseFlex::SetPermitResponse( float endtime )
  1648. {
  1649. // Mark time after which we'll be occupied again (if in a scene)
  1650. // Note a value of <= 0.0f means unset (always allow actor to speak if not in a scene,
  1651. // and always disallow if in a scene)
  1652. m_flAllowResponsesEndTime = endtime;
  1653. }
  1654. //-----------------------------------------------------------------------------
  1655. // Purpose: Play a one-shot scene
  1656. // Input :
  1657. // Output :
  1658. //-----------------------------------------------------------------------------
  1659. float CBaseFlex::PlayScene( const char *pszScene, float flDelay, AI_Response *response, IRecipientFilter *filter /* = NULL */ )
  1660. {
  1661. return InstancedScriptedScene( this, pszScene, NULL, flDelay, false, response, false, filter );
  1662. }
  1663. //-----------------------------------------------------------------------------
  1664. // Purpose: Generate a one-shot scene in memory with one track which is to play the named sound on the actor
  1665. // Input : *soundname -
  1666. // Output : float
  1667. //-----------------------------------------------------------------------------
  1668. float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname )
  1669. {
  1670. return InstancedAutoGeneratedSoundScene( this, soundname );
  1671. }
  1672. // FIXME: move to CBaseActor
  1673. bool CBaseFlex::EnterSceneSequence( CChoreoScene *scene, CChoreoEvent *event, bool bRestart )
  1674. {
  1675. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1676. if (!myNpc)
  1677. {
  1678. // In multiplayer, we allow players to play scenes
  1679. if ( IsPlayer() )
  1680. return true;
  1681. return false;
  1682. }
  1683. // 2 seconds past current event, or 0.2 seconds past end of scene, whichever is shorter
  1684. float flDuration = MIN( 2.0, MIN( event->GetEndTime() - scene->GetTime() + 2.0, scene->FindStopTime() - scene->GetTime() + 0.2 ) );
  1685. if (myNpc->IsCurSchedule( SCHED_SCENE_GENERIC ))
  1686. {
  1687. myNpc->AddSceneLock( flDuration );
  1688. return true;
  1689. }
  1690. // for now, don't interrupt sequences that don't understand being interrupted
  1691. if (myNpc->GetCurSchedule())
  1692. {
  1693. CAI_ScheduleBits testBits;
  1694. myNpc->GetCurSchedule()->GetInterruptMask( &testBits );
  1695. testBits.Clear( COND_PROVOKED );
  1696. if (testBits.IsAllClear())
  1697. {
  1698. return false;
  1699. }
  1700. }
  1701. if (myNpc->IsInterruptable())
  1702. {
  1703. if (myNpc->m_hCine)
  1704. {
  1705. // Assert( !(myNpc->GetFlags() & FL_FLY ) );
  1706. myNpc->ExitScriptedSequence( );
  1707. }
  1708. myNpc->OnStartScene();
  1709. myNpc->SetSchedule( SCHED_SCENE_GENERIC );
  1710. myNpc->AddSceneLock( flDuration );
  1711. return true;
  1712. }
  1713. return false;
  1714. }
  1715. bool CBaseFlex::ExitSceneSequence( void )
  1716. {
  1717. return true;
  1718. }
  1719. //-----------------------------------------------------------------------------
  1720. // Purpose: keep track of last valid flex animation time and returns if the current info should play theirs
  1721. //-----------------------------------------------------------------------------
  1722. bool CBaseFlex::IsSuppressedFlexAnimation( CSceneEventInfo *info )
  1723. {
  1724. // check for suppression if the current info is a background
  1725. if (info->m_pScene && info->m_pScene->IsBackground())
  1726. {
  1727. // allow for slight jitter
  1728. return m_flLastFlexAnimationTime > gpGlobals->curtime - GetAnimTimeInterval() * 1.5;
  1729. }
  1730. // keep track of last non-suppressable flex animation
  1731. m_flLastFlexAnimationTime = gpGlobals->curtime;
  1732. return false;
  1733. }
  1734. //-----------------------------------------------------------------------------
  1735. // Purpose: Clear out body lean states that are invalidated with Teleport
  1736. //-----------------------------------------------------------------------------
  1737. void CBaseFlex::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
  1738. {
  1739. BaseClass::Teleport( newPosition, newAngles, newVelocity );
  1740. #ifdef HL2_DLL
  1741. // clear out Body Lean
  1742. m_vecPrevOrigin = vec3_origin;
  1743. #endif
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Purpose: keep track of accel/decal and lean the body
  1747. //-----------------------------------------------------------------------------
  1748. void CBaseFlex::DoBodyLean( void )
  1749. {
  1750. #ifdef HL2_DLL
  1751. CAI_BaseNPC *myNpc = MyNPCPointer( );
  1752. if (myNpc)
  1753. {
  1754. Vector vecDelta;
  1755. Vector vecPos;
  1756. Vector vecOrigin = GetAbsOrigin();
  1757. if (m_vecPrevOrigin == vec3_origin)
  1758. {
  1759. m_vecPrevOrigin = vecOrigin;
  1760. }
  1761. vecDelta = vecOrigin - m_vecPrevOrigin;
  1762. vecDelta.x = clamp( vecDelta.x, -50, 50 );
  1763. vecDelta.y = clamp( vecDelta.y, -50, 50 );
  1764. vecDelta.z = clamp( vecDelta.z, -50, 50 );
  1765. float dt = gpGlobals->curtime - GetLastThink();
  1766. bool bSkip = ((GetFlags() & (FL_FLY | FL_SWIM)) != 0) || (GetMoveParent() != NULL) || (GetGroundEntity() == NULL) || (GetGroundEntity()->IsMoving());
  1767. bSkip |= myNpc->TaskRanAutomovement() || (myNpc->GetVehicleEntity() != NULL);
  1768. if (!bSkip)
  1769. {
  1770. if (vecDelta.LengthSqr() > m_vecPrevVelocity.LengthSqr())
  1771. {
  1772. float decay = ExponentialDecay( 0.6, 0.1, dt );
  1773. m_vecPrevVelocity = m_vecPrevVelocity * (decay) + vecDelta * (1.f - decay);
  1774. }
  1775. else
  1776. {
  1777. float decay = ExponentialDecay( 0.4, 0.1, dt );
  1778. m_vecPrevVelocity = m_vecPrevVelocity * (decay) + vecDelta * (1.f - decay);
  1779. }
  1780. vecPos = m_vecPrevOrigin + m_vecPrevVelocity;
  1781. float decay = ExponentialDecay( 0.5, 0.1, dt );
  1782. m_vecShift = m_vecShift * (decay) + (vecOrigin - vecPos) * (1.f - decay); // FIXME: Scale this
  1783. m_vecLean = (vecOrigin - vecPos) * 1.0; // FIXME: Scale this
  1784. }
  1785. else
  1786. {
  1787. m_vecPrevVelocity = vecDelta;
  1788. float decay = ExponentialDecay( 0.5, 0.1, dt );
  1789. m_vecShift = m_vecLean * decay;
  1790. m_vecLean = m_vecShift * decay;
  1791. }
  1792. m_vecPrevOrigin = vecOrigin;
  1793. /*
  1794. DevMsg( "%.2f %.2f %.2f (%.2f %.2f %.2f)\n",
  1795. m_vecLean.Get().x, m_vecLean.Get().y, m_vecLean.Get().z,
  1796. vecDelta.x, vecDelta.y, vecDelta.z );
  1797. */
  1798. }
  1799. #endif
  1800. }
  1801. //-----------------------------------------------------------------------------
  1802. // Purpose: initialize weight for background events
  1803. //-----------------------------------------------------------------------------
  1804. void CSceneEventInfo::InitWeight( CBaseFlex *pActor )
  1805. {
  1806. if (pActor->IsSuppressedFlexAnimation( this ))
  1807. {
  1808. m_flWeight = 0.0;
  1809. }
  1810. else
  1811. {
  1812. m_flWeight = 1.0;
  1813. }
  1814. }
  1815. //-----------------------------------------------------------------------------
  1816. // Purpose: update weight for background events. Only call once per think
  1817. //-----------------------------------------------------------------------------
  1818. float CSceneEventInfo::UpdateWeight( CBaseFlex *pActor )
  1819. {
  1820. // decay if this is a background scene and there's other flex animations playing
  1821. if (pActor->IsSuppressedFlexAnimation( this ))
  1822. {
  1823. m_flWeight = MAX( m_flWeight - 0.2, 0.0 );
  1824. }
  1825. else
  1826. {
  1827. m_flWeight = MIN( m_flWeight + 0.1, 1.0 );
  1828. }
  1829. return m_flWeight;
  1830. }
  1831. //-----------------------------------------------------------------------------
  1832. // Purpose:
  1833. //-----------------------------------------------------------------------------
  1834. class CFlexCycler : public CBaseFlex
  1835. {
  1836. private:
  1837. DECLARE_CLASS( CFlexCycler, CBaseFlex );
  1838. public:
  1839. DECLARE_DATADESC();
  1840. CFlexCycler() { m_iszSentence = NULL_STRING; m_sentence = 0; }
  1841. void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax);
  1842. virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE); }
  1843. int OnTakeDamage( const CTakeDamageInfo &info );
  1844. void Spawn( void );
  1845. void Think( void );
  1846. virtual void ProcessSceneEvents( void );
  1847. // Don't treat as a live target
  1848. virtual bool IsAlive( void ) { return FALSE; }
  1849. float m_flextime;
  1850. LocalFlexController_t m_flexnum;
  1851. float m_flextarget[64];
  1852. float m_blinktime;
  1853. float m_looktime;
  1854. Vector m_lookTarget;
  1855. float m_speaktime;
  1856. int m_istalking;
  1857. int m_phoneme;
  1858. string_t m_iszSentence;
  1859. int m_sentence;
  1860. void SetFlexTarget( LocalFlexController_t flexnum );
  1861. LocalFlexController_t LookupFlex( const char *szTarget );
  1862. };
  1863. BEGIN_DATADESC( CFlexCycler )
  1864. DEFINE_FIELD( m_flextime, FIELD_TIME ),
  1865. DEFINE_FIELD( m_flexnum, FIELD_INTEGER ),
  1866. DEFINE_ARRAY( m_flextarget, FIELD_FLOAT, 64 ),
  1867. DEFINE_FIELD( m_blinktime, FIELD_TIME ),
  1868. DEFINE_FIELD( m_looktime, FIELD_TIME ),
  1869. DEFINE_FIELD( m_lookTarget, FIELD_POSITION_VECTOR ),
  1870. DEFINE_FIELD( m_speaktime, FIELD_TIME ),
  1871. DEFINE_FIELD( m_istalking, FIELD_INTEGER ),
  1872. DEFINE_FIELD( m_phoneme, FIELD_INTEGER ),
  1873. DEFINE_KEYFIELD( m_iszSentence, FIELD_STRING, "Sentence" ),
  1874. DEFINE_FIELD( m_sentence, FIELD_INTEGER ),
  1875. END_DATADESC()
  1876. //
  1877. // we should get rid of all the other cyclers and replace them with this.
  1878. //
  1879. class CGenericFlexCycler : public CFlexCycler
  1880. {
  1881. public:
  1882. DECLARE_CLASS( CGenericFlexCycler, CFlexCycler );
  1883. void Spawn( void ) { GenericCyclerSpawn( (char *)STRING( GetModelName() ), Vector(-16, -16, 0), Vector(16, 16, 72) ); }
  1884. };
  1885. LINK_ENTITY_TO_CLASS( cycler_flex, CGenericFlexCycler );
  1886. ConVar flex_expression( "flex_expression","-" );
  1887. ConVar flex_talk( "flex_talk","0" );
  1888. // Cycler member functions
  1889. void CFlexCycler::GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax)
  1890. {
  1891. if (!szModel || !*szModel)
  1892. {
  1893. Warning( "cycler at %.0f %.0f %0.f missing modelname\n", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
  1894. UTIL_Remove( this );
  1895. return;
  1896. }
  1897. PrecacheModel( szModel );
  1898. SetModel( szModel );
  1899. CFlexCycler::Spawn( );
  1900. UTIL_SetSize(this, vecMin, vecMax);
  1901. Vector vecEyeOffset;
  1902. GetEyePosition( GetModelPtr(), vecEyeOffset );
  1903. SetViewOffset( vecEyeOffset );
  1904. InitBoneControllers();
  1905. if (GetNumFlexControllers() < 5)
  1906. Warning( "cycler_flex used on model %s without enough flexes.\n", szModel );
  1907. }
  1908. void CFlexCycler::Spawn( )
  1909. {
  1910. Precache();
  1911. /*
  1912. if ( m_spawnflags & FCYCLER_NOTSOLID )
  1913. {
  1914. SetSolid( SOLID_NOT );
  1915. }
  1916. else
  1917. {
  1918. SetSolid( SOLID_SLIDEBOX );
  1919. }
  1920. */
  1921. SetSolid( SOLID_BBOX );
  1922. AddSolidFlags( FSOLID_NOT_STANDABLE );
  1923. SetMoveType( MOVETYPE_NONE );
  1924. m_takedamage = DAMAGE_YES;
  1925. m_iHealth = 80000;// no cycler should die
  1926. m_flPlaybackRate = 1.0f;
  1927. m_flGroundSpeed = 0;
  1928. SetNextThink( gpGlobals->curtime + 1.0f );
  1929. ResetSequenceInfo( );
  1930. m_flCycle = random->RandomFloat( 0, 1.0 );
  1931. }
  1932. const char *predef_flexcontroller_names[] = {
  1933. "right_lid_raiser",
  1934. "left_lid_raiser",
  1935. "right_lid_tightener",
  1936. "left_lid_tightener",
  1937. "right_lid_droop",
  1938. "left_lid_droop",
  1939. "right_inner_raiser",
  1940. "left_inner_raiser",
  1941. "right_outer_raiser",
  1942. "left_outer_raiser",
  1943. "right_lowerer",
  1944. "left_lowerer",
  1945. "right_cheek_raiser",
  1946. "left_cheek_raiser",
  1947. "wrinkler",
  1948. "right_upper_raiser",
  1949. "left_upper_raiser",
  1950. "right_corner_puller",
  1951. "left_corner_puller",
  1952. "corner_depressor",
  1953. "chin_raiser",
  1954. "right_puckerer",
  1955. "left_puckerer",
  1956. "right_funneler",
  1957. "left_funneler",
  1958. "tightener",
  1959. "jaw_clencher",
  1960. "jaw_drop",
  1961. "right_mouth_drop",
  1962. "left_mouth_drop",
  1963. NULL };
  1964. float predef_flexcontroller_values[7][30] = {
  1965. /* 0 */ { 0.700,0.560,0.650,0.650,0.650,0.585,0.000,0.000,0.400,0.040,0.000,0.000,0.450,0.450,0.000,0.000,0.000,0.750,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.150,1.000,0.000,0.000,0.000 },
  1966. /* 1 */ { 0.450,0.450,0.450,0.450,0.000,0.000,0.000,0.000,0.300,0.300,0.000,0.000,0.250,0.250,0.000,0.000,0.000,0.750,0.750,0.000,0.000,0.000,0.000,0.400,0.400,0.000,1.000,0.000,0.050,0.050 },
  1967. /* 2 */ { 0.200,0.200,0.500,0.500,0.150,0.150,0.100,0.100,0.150,0.150,0.000,0.000,0.700,0.700,0.000,0.000,0.000,0.750,0.750,0.000,0.200,0.000,0.000,0.000,0.000,0.000,0.850,0.000,0.000,0.000 },
  1968. /* 3 */ { 0.000,0.000,0.000,0.000,0.000,0.000,0.300,0.300,0.000,0.000,0.000,0.000,0.000,0.000,0.100,0.000,0.000,0.000,0.000,0.700,0.300,0.000,0.000,0.200,0.200,0.000,0.000,0.300,0.000,0.000 },
  1969. /* 4 */ { 0.450,0.450,0.000,0.000,0.450,0.450,0.000,0.000,0.000,0.000,0.450,0.450,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.300,0.000,0.000,0.000,0.000 },
  1970. /* 5 */ { 0.000,0.000,0.350,0.350,0.150,0.150,0.300,0.300,0.450,0.450,0.000,0.000,0.200,0.200,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.200,0.200,0.000,0.000,0.300,0.000,0.000,0.000,0.000 },
  1971. /* 6 */ { 0.000,0.000,0.650,0.650,0.750,0.750,0.000,0.000,0.000,0.000,0.300,0.300,0.000,0.000,0.000,0.250,0.250,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000 }
  1972. };
  1973. //-----------------------------------------------------------------------------
  1974. // Purpose: Changes sequences when shot
  1975. //-----------------------------------------------------------------------------
  1976. int CFlexCycler::OnTakeDamage( const CTakeDamageInfo &info )
  1977. {
  1978. int nSequence = GetSequence() + 1;
  1979. if (!IsValidSequence( nSequence ))
  1980. {
  1981. nSequence = 0;
  1982. }
  1983. ResetSequence( nSequence );
  1984. m_flCycle = 0;
  1985. return 0;
  1986. }
  1987. void CFlexCycler::SetFlexTarget( LocalFlexController_t flexnum )
  1988. {
  1989. m_flextarget[flexnum] = random->RandomFloat( 0.5, 1.0 );
  1990. const char *pszType = GetFlexControllerType( flexnum );
  1991. // zero out all other flexes of the same type
  1992. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  1993. {
  1994. if (i != flexnum)
  1995. {
  1996. const char *pszOtherType = GetFlexControllerType( i );
  1997. if (stricmp( pszType, pszOtherType ) == 0)
  1998. {
  1999. m_flextarget[i] = 0;
  2000. }
  2001. }
  2002. }
  2003. // HACK, for now, consider then linked is named "right_" or "left_"
  2004. if (strncmp( "right_", GetFlexControllerName( flexnum ), 6 ) == 0)
  2005. {
  2006. m_flextarget[flexnum+1] = m_flextarget[flexnum];
  2007. }
  2008. else if (strncmp( "left_", GetFlexControllerName( flexnum ), 5 ) == 0)
  2009. {
  2010. m_flextarget[flexnum-1] = m_flextarget[flexnum];
  2011. }
  2012. }
  2013. LocalFlexController_t CFlexCycler::LookupFlex( const char *szTarget )
  2014. {
  2015. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  2016. {
  2017. const char *pszFlex = GetFlexControllerName( i );
  2018. if (stricmp( szTarget, pszFlex ) == 0)
  2019. {
  2020. return i;
  2021. }
  2022. }
  2023. return LocalFlexController_t(-1);
  2024. }
  2025. void CFlexCycler::Think( void )
  2026. {
  2027. SetNextThink( gpGlobals->curtime + 0.1f );
  2028. StudioFrameAdvance ( );
  2029. if (IsSequenceFinished() && !SequenceLoops())
  2030. {
  2031. // ResetSequenceInfo();
  2032. // hack to avoid reloading model every frame
  2033. m_flAnimTime = gpGlobals->curtime;
  2034. m_flPlaybackRate = 1.0;
  2035. m_bSequenceFinished = false;
  2036. m_flLastEventCheck = 0;
  2037. m_flCycle = 0;
  2038. }
  2039. // only do this if they have more than eyelid movement
  2040. if (GetNumFlexControllers() > 2)
  2041. {
  2042. const char *pszExpression = flex_expression.GetString();
  2043. if (pszExpression && pszExpression[0] == '+' && pszExpression[1] != '\0')
  2044. {
  2045. int i;
  2046. int j = atoi( &pszExpression[1] );
  2047. for ( i = 0; i < GetNumFlexControllers(); i++)
  2048. {
  2049. m_flextarget[m_flexnum] = 0;
  2050. }
  2051. for (i = 0; i < 35 && predef_flexcontroller_names[i]; i++)
  2052. {
  2053. m_flexnum = LookupFlex( predef_flexcontroller_names[i] );
  2054. m_flextarget[m_flexnum] = predef_flexcontroller_values[j][i];
  2055. // Msg( "%s %.3f\n", predef_flexcontroller_names[i], predef_flexcontroller_values[j][i] );
  2056. }
  2057. }
  2058. else if ( pszExpression && (pszExpression[0] == '1') && (pszExpression[1] == '\0') ) // 1 for maxed controller values
  2059. {
  2060. for ( LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++ )
  2061. {
  2062. // Max everything out...
  2063. m_flextarget[i] = 1.0f;
  2064. SetFlexWeight( i, m_flextarget[i] );
  2065. }
  2066. }
  2067. else if ( pszExpression && (pszExpression[0] == '^') && (pszExpression[1] == '\0') ) // ^ for sine wave
  2068. {
  2069. for ( LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++ )
  2070. {
  2071. // Throw a differently offset sine wave on all of the flex controllers
  2072. float fFlexTime = i * (1.0f / (float)GetNumFlexControllers()) + gpGlobals->curtime;
  2073. m_flextarget[i] = sinf( fFlexTime ) * 0.5f + 0.5f;
  2074. SetFlexWeight( i, m_flextarget[i] );
  2075. }
  2076. }
  2077. else if (pszExpression && pszExpression[0] != '\0' && strcmp(pszExpression, "+") != 0)
  2078. {
  2079. char szExpression[128];
  2080. char szTemp[32];
  2081. Q_strncpy( szExpression, pszExpression ,sizeof(szExpression));
  2082. char *pszExpression = szExpression;
  2083. while (*pszExpression != '\0')
  2084. {
  2085. if (*pszExpression == '+')
  2086. *pszExpression = ' ';
  2087. pszExpression++;
  2088. }
  2089. pszExpression = szExpression;
  2090. while (*pszExpression)
  2091. {
  2092. if (*pszExpression != ' ')
  2093. {
  2094. if (*pszExpression == '-')
  2095. {
  2096. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  2097. {
  2098. m_flextarget[i] = 0;
  2099. }
  2100. }
  2101. else if (*pszExpression == '?')
  2102. {
  2103. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  2104. {
  2105. Msg( "\"%s\" ", GetFlexControllerName( i ) );
  2106. }
  2107. Msg( "\n" );
  2108. flex_expression.SetValue( "" );
  2109. }
  2110. else
  2111. {
  2112. if (sscanf( pszExpression, "%31s", szTemp ) == 1)
  2113. {
  2114. m_flexnum = LookupFlex( szTemp );
  2115. if (m_flexnum != LocalFlexController_t(-1) && m_flextarget[m_flexnum] != 1)
  2116. {
  2117. m_flextarget[m_flexnum] = 1.0;
  2118. // SetFlexTarget( m_flexnum );
  2119. }
  2120. pszExpression += strlen( szTemp ) - 1;
  2121. }
  2122. }
  2123. }
  2124. pszExpression++;
  2125. }
  2126. }
  2127. else if (m_flextime < gpGlobals->curtime)
  2128. {
  2129. // m_flextime = gpGlobals->curtime + 1.0; // RandomFloat( 0.1, 0.5 );
  2130. m_flextime = gpGlobals->curtime + random->RandomFloat( 0.3, 0.5 ) * (30.0 / GetNumFlexControllers());
  2131. m_flexnum = (LocalFlexController_t)random->RandomInt( 0, GetNumFlexControllers() - 1 );
  2132. // m_flexnum = (pflex->num + 1) % r_psubmodel->numflexes;
  2133. if (m_flextarget[m_flexnum] == 1)
  2134. {
  2135. m_flextarget[m_flexnum] = 0;
  2136. // pflex->time = cl.time + 0.1;
  2137. }
  2138. else if (stricmp( GetFlexControllerType( m_flexnum ), "phoneme" ) != 0)
  2139. {
  2140. if (strstr( GetFlexControllerName( m_flexnum ), "upper_raiser" ) == NULL)
  2141. {
  2142. Msg( "%s:%s\n", GetFlexControllerType( m_flexnum ), GetFlexControllerName( m_flexnum ) );
  2143. SetFlexTarget( m_flexnum );
  2144. }
  2145. }
  2146. #if 0
  2147. char szWhat[256];
  2148. szWhat[0] = '\0';
  2149. for (int i = 0; i < GetNumFlexControllers(); i++)
  2150. {
  2151. if (m_flextarget[i] == 1.0)
  2152. {
  2153. if (stricmp( GetFlexFacs( i ), "upper") != 0 && stricmp( GetFlexFacs( i ), "lower") != 0)
  2154. {
  2155. if (szWhat[0] == '\0')
  2156. Q_strncat( szWhat, "-", sizeof( szWhat ), COPY_ALL_CHARACTERS );
  2157. else
  2158. Q_strncat( szWhat, "+", sizeof( szWhat ), COPY_ALL_CHARACTERS );
  2159. Q_strncat( szWhat, GetFlexFacs( i ), sizeof( szWhat ), COPY_ALL_CHARACTERS );
  2160. }
  2161. }
  2162. }
  2163. Msg( "%s\n", szWhat );
  2164. #endif
  2165. }
  2166. // slide it up.
  2167. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  2168. {
  2169. float weight = GetFlexWeight( i );
  2170. if (weight != m_flextarget[i])
  2171. {
  2172. weight = weight + (m_flextarget[i] - weight) / random->RandomFloat( 2.0, 4.0 );
  2173. }
  2174. weight = clamp( weight, 0.0f, 1.0f );
  2175. SetFlexWeight( i, weight );
  2176. }
  2177. #if 1
  2178. if (flex_talk.GetInt() == -1)
  2179. {
  2180. m_istalking = 1;
  2181. char pszSentence[256];
  2182. Q_snprintf( pszSentence,sizeof(pszSentence), "%s%d", STRING(m_iszSentence), m_sentence++ );
  2183. int sentenceIndex = engine->SentenceIndexFromName( pszSentence );
  2184. if (sentenceIndex >= 0)
  2185. {
  2186. Msg( "%d : %s\n", sentenceIndex, pszSentence );
  2187. CPASAttenuationFilter filter( this );
  2188. CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, SNDLVL_TALKING, 0, PITCH_NORM );
  2189. }
  2190. else
  2191. {
  2192. m_sentence = 0;
  2193. }
  2194. flex_talk.SetValue( "0" );
  2195. }
  2196. else if (!FStrEq( flex_talk.GetString(), "0") )
  2197. {
  2198. int sentenceIndex = engine->SentenceIndexFromName( flex_talk.GetString() );
  2199. if (sentenceIndex >= 0)
  2200. {
  2201. CPASAttenuationFilter filter( this );
  2202. CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, SNDLVL_TALKING, 0, PITCH_NORM );
  2203. }
  2204. flex_talk.SetValue( "0" );
  2205. }
  2206. #else
  2207. if (flex_talk.GetInt())
  2208. {
  2209. if (m_speaktime < gpGlobals->curtime)
  2210. {
  2211. if (m_phoneme == 0)
  2212. {
  2213. for (m_phoneme = 0; m_phoneme < GetNumFlexControllers(); m_phoneme++)
  2214. {
  2215. if (stricmp( GetFlexFacs( m_phoneme ), "27") == 0)
  2216. break;
  2217. }
  2218. }
  2219. m_istalking = !m_istalking;
  2220. if (m_istalking)
  2221. {
  2222. m_looktime = gpGlobals->curtime - 1.0;
  2223. m_speaktime = gpGlobals->curtime + random->RandomFloat( 0.5, 2.0 );
  2224. }
  2225. else
  2226. {
  2227. m_speaktime = gpGlobals->curtime + random->RandomFloat( 1.0, 3.0 );
  2228. }
  2229. }
  2230. for (i = m_phoneme; i < GetNumFlexControllers(); i++)
  2231. {
  2232. SetFlexWeight( i, 0.0f );
  2233. }
  2234. if (m_istalking)
  2235. {
  2236. m_flextime = gpGlobals->curtime + random->RandomFloat( 0.0, 0.2 );
  2237. m_flexWeight[random->RandomInt(m_phoneme, GetNumFlexControllers()-1)] = random->RandomFloat( 0.5, 1.0 );
  2238. float mouth = random->RandomFloat( 0.0, 1.0 );
  2239. float jaw = random->RandomFloat( 0.0, 1.0 );
  2240. m_flexWeight[m_phoneme - 2] = jaw * (mouth);
  2241. m_flexWeight[m_phoneme - 1] = jaw * (1.0 - mouth);
  2242. }
  2243. }
  2244. else
  2245. {
  2246. m_istalking = 0;
  2247. }
  2248. #endif
  2249. // blink
  2250. if (m_blinktime < gpGlobals->curtime)
  2251. {
  2252. Blink();
  2253. m_blinktime = gpGlobals->curtime + random->RandomFloat( 1.5, 4.5 );
  2254. }
  2255. }
  2256. Vector forward, right, up;
  2257. GetVectors( &forward, &right, &up );
  2258. CBaseEntity *pPlayer = (CBaseEntity *)UTIL_GetLocalPlayer();
  2259. if (pPlayer)
  2260. {
  2261. if (pPlayer->GetSmoothedVelocity().Length() != 0 && DotProduct( forward, pPlayer->EyePosition() - EyePosition()) > 0.5)
  2262. {
  2263. m_lookTarget = pPlayer->EyePosition();
  2264. m_looktime = gpGlobals->curtime + random->RandomFloat(2.0,4.0);
  2265. }
  2266. else if (m_looktime < gpGlobals->curtime)
  2267. {
  2268. if ((!m_istalking) && random->RandomInt( 0, 1 ) == 0)
  2269. {
  2270. m_lookTarget = EyePosition() + forward * 128 + right * random->RandomFloat(-64,64) + up * random->RandomFloat(-32,32);
  2271. m_looktime = gpGlobals->curtime + random->RandomFloat(0.3,1.0);
  2272. if (m_blinktime - 0.5 < gpGlobals->curtime)
  2273. {
  2274. Blink();
  2275. }
  2276. }
  2277. else
  2278. {
  2279. m_lookTarget = pPlayer->EyePosition();
  2280. m_looktime = gpGlobals->curtime + random->RandomFloat(1.0,4.0);
  2281. }
  2282. }
  2283. #if 0
  2284. float dt = acos( DotProduct( (m_lookTarget - EyePosition()).Normalize(), (m_viewtarget - EyePosition()).Normalize() ) );
  2285. if (dt > M_PI / 4)
  2286. {
  2287. dt = (M_PI / 4) * dt;
  2288. m_viewtarget = ((1 - dt) * m_viewtarget + dt * m_lookTarget);
  2289. }
  2290. #endif
  2291. SetViewtarget( m_lookTarget );
  2292. }
  2293. // Handle any facial animation from scene playback
  2294. // FIXME: do we still actually need flex cyclers?
  2295. // AddSceneSceneEvents();
  2296. }
  2297. void CFlexCycler::ProcessSceneEvents( void )
  2298. {
  2299. // Don't do anything since we handle facial stuff in Think()
  2300. }
  2301. BEGIN_BYTESWAP_DATADESC( flexsettinghdr_t )
  2302. DEFINE_FIELD( id, FIELD_INTEGER ),
  2303. DEFINE_FIELD( version, FIELD_INTEGER ),
  2304. DEFINE_ARRAY( name, FIELD_CHARACTER, 64 ),
  2305. DEFINE_FIELD( length, FIELD_INTEGER ),
  2306. DEFINE_FIELD( numflexsettings, FIELD_INTEGER ),
  2307. DEFINE_FIELD( flexsettingindex, FIELD_INTEGER ),
  2308. DEFINE_FIELD( nameindex, FIELD_INTEGER ),
  2309. DEFINE_FIELD( numindexes, FIELD_INTEGER ),
  2310. DEFINE_FIELD( indexindex, FIELD_INTEGER ),
  2311. DEFINE_FIELD( numkeys, FIELD_INTEGER ),
  2312. DEFINE_FIELD( keynameindex, FIELD_INTEGER ),
  2313. DEFINE_FIELD( keymappingindex, FIELD_INTEGER ),
  2314. END_BYTESWAP_DATADESC()
  2315. BEGIN_BYTESWAP_DATADESC( flexsetting_t )
  2316. DEFINE_FIELD( nameindex, FIELD_INTEGER ),
  2317. DEFINE_FIELD( obsolete1, FIELD_INTEGER ),
  2318. DEFINE_FIELD( numsettings, FIELD_INTEGER ),
  2319. DEFINE_FIELD( index, FIELD_INTEGER ),
  2320. DEFINE_FIELD( obsolete2, FIELD_INTEGER ),
  2321. DEFINE_FIELD( settingindex, FIELD_INTEGER ),
  2322. END_BYTESWAP_DATADESC()
  2323. BEGIN_BYTESWAP_DATADESC( flexweight_t )
  2324. DEFINE_FIELD( key, FIELD_INTEGER ),
  2325. DEFINE_FIELD( weight, FIELD_FLOAT ),
  2326. DEFINE_FIELD( influence, FIELD_FLOAT ),
  2327. END_BYTESWAP_DATADESC()