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.

846 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "IEffects.h"
  9. #include "collisionutils.h"
  10. #include "ai_basenpc.h"
  11. #include "ai_scriptconditions.h"
  12. #include "saverestore_utlvector.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. #define SF_ACTOR_AS_ACTIVATOR ( 1 << 0 )
  16. ConVar debugscriptconditions( "ai_debugscriptconditions", "0" );
  17. #define ScrCondDbgMsg( msg ) \
  18. do \
  19. { \
  20. if ( debugscriptconditions.GetBool() ) \
  21. { \
  22. DevMsg msg; \
  23. } \
  24. } \
  25. while (0)
  26. //=============================================================================
  27. //
  28. // CAI_ScriptConditions
  29. //
  30. //=============================================================================
  31. LINK_ENTITY_TO_CLASS(ai_script_conditions, CAI_ScriptConditions);
  32. BEGIN_DATADESC( CAI_ScriptConditions )
  33. DEFINE_THINKFUNC( EvaluationThink ),
  34. DEFINE_OUTPUT( m_OnConditionsSatisfied, "OnConditionsSatisfied" ),
  35. DEFINE_OUTPUT( m_OnConditionsTimeout, "OnConditionsTimeout" ),
  36. DEFINE_OUTPUT( m_NoValidActors, "NoValidActors" ),
  37. //---------------------------------
  38. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  39. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  40. //---------------------------------
  41. // Inputs
  42. DEFINE_KEYFIELD(m_fDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  43. DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
  44. DEFINE_KEYFIELD(m_Actor, FIELD_STRING, "Actor" ),
  45. DEFINE_KEYFIELD(m_flRequiredTime, FIELD_FLOAT, "RequiredTime" ),
  46. #ifndef HL2_EPISODIC
  47. DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
  48. DEFINE_EMBEDDED(m_Timer ),
  49. DEFINE_EMBEDDED(m_Timeout ),
  50. #endif
  51. DEFINE_KEYFIELD(m_fMinState, FIELD_INTEGER, "MinimumState" ),
  52. DEFINE_KEYFIELD(m_fMaxState, FIELD_INTEGER, "MaximumState" ),
  53. DEFINE_KEYFIELD(m_fScriptStatus, FIELD_INTEGER, "ScriptStatus" ),
  54. DEFINE_KEYFIELD(m_fActorSeePlayer, FIELD_INTEGER, "ActorSeePlayer" ),
  55. DEFINE_KEYFIELD(m_flPlayerActorProximity, FIELD_FLOAT, "PlayerActorProximity" ),
  56. DEFINE_EMBEDDED(m_PlayerActorProxTester),
  57. DEFINE_KEYFIELD(m_flPlayerActorFOV, FIELD_FLOAT, "PlayerActorFOV" ),
  58. DEFINE_KEYFIELD(m_bPlayerActorFOVTrueCone, FIELD_BOOLEAN, "PlayerActorFOVTrueCone" ),
  59. DEFINE_KEYFIELD(m_fPlayerActorLOS, FIELD_INTEGER, "PlayerActorLOS" ),
  60. DEFINE_KEYFIELD(m_fActorSeeTarget, FIELD_INTEGER, "ActorSeeTarget" ),
  61. DEFINE_KEYFIELD(m_flActorTargetProximity, FIELD_FLOAT, "ActorTargetProximity" ),
  62. DEFINE_EMBEDDED(m_ActorTargetProxTester),
  63. DEFINE_KEYFIELD(m_flPlayerTargetProximity, FIELD_FLOAT, "PlayerTargetProximity" ),
  64. DEFINE_EMBEDDED(m_PlayerTargetProxTester),
  65. DEFINE_KEYFIELD(m_flPlayerTargetFOV, FIELD_FLOAT, "PlayerTargetFOV" ),
  66. DEFINE_KEYFIELD(m_bPlayerTargetFOVTrueCone, FIELD_BOOLEAN, "PlayerTargetFOVTrueCone" ),
  67. DEFINE_KEYFIELD(m_fPlayerTargetLOS, FIELD_INTEGER, "PlayerTargetLOS" ),
  68. DEFINE_KEYFIELD(m_fPlayerBlockingActor, FIELD_INTEGER, "PlayerBlockingActor" ),
  69. DEFINE_KEYFIELD(m_flMinTimeout, FIELD_FLOAT, "MinTimeout" ),
  70. DEFINE_KEYFIELD(m_flMaxTimeout, FIELD_FLOAT, "MaxTimeout" ),
  71. DEFINE_KEYFIELD(m_fActorInPVS, FIELD_INTEGER, "ActorInPVS" ),
  72. DEFINE_KEYFIELD(m_fActorInVehicle, FIELD_INTEGER, "ActorInVehicle" ),
  73. DEFINE_KEYFIELD(m_fPlayerInVehicle, FIELD_INTEGER, "PlayerInVehicle" ),
  74. DEFINE_UTLVECTOR( m_ElementList, FIELD_EMBEDDED ),
  75. DEFINE_FIELD( m_bLeaveAsleep, FIELD_BOOLEAN ),
  76. END_DATADESC()
  77. BEGIN_SIMPLE_DATADESC( CAI_ProxTester )
  78. DEFINE_FIELD( m_distSq, FIELD_FLOAT ),
  79. DEFINE_FIELD( m_fInside, FIELD_BOOLEAN ),
  80. END_DATADESC()
  81. BEGIN_SIMPLE_DATADESC( CAI_ScriptConditionsElement )
  82. DEFINE_FIELD( m_hActor, FIELD_EHANDLE ),
  83. DEFINE_EMBEDDED(m_Timer ),
  84. DEFINE_EMBEDDED(m_Timeout ),
  85. END_DATADESC()
  86. //-----------------------------------------------------------------------------
  87. #define EVALUATOR( name ) { &CAI_ScriptConditions::Eval##name, #name }
  88. CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
  89. {
  90. EVALUATOR( ActorSeePlayer ),
  91. EVALUATOR( State ),
  92. EVALUATOR( PlayerActorProximity ),
  93. EVALUATOR( PlayerTargetProximity ),
  94. EVALUATOR( ActorTargetProximity ),
  95. EVALUATOR( PlayerBlockingActor ),
  96. EVALUATOR( PlayerActorLook ),
  97. EVALUATOR( PlayerTargetLook ),
  98. EVALUATOR( ActorSeeTarget),
  99. EVALUATOR( PlayerActorLOS ),
  100. EVALUATOR( PlayerTargetLOS ),
  101. #ifdef HL2_EPISODIC
  102. EVALUATOR( ActorInPVS ),
  103. EVALUATOR( PlayerInVehicle ),
  104. EVALUATOR( ActorInVehicle ),
  105. #endif
  106. };
  107. void CAI_ScriptConditions::OnRestore( void )
  108. {
  109. BaseClass::OnRestore();
  110. #ifndef HL2_EPISODIC
  111. //Old HL2 save game! Fix up to new system.
  112. if ( m_hActor )
  113. {
  114. CAI_ScriptConditionsElement conditionactor;
  115. conditionactor.SetActor( m_hActor );
  116. conditionactor.SetTimeOut( m_Timeout );
  117. conditionactor.SetTimer( m_Timer );
  118. m_ElementList.AddToTail( conditionactor );
  119. m_hActor = NULL;
  120. }
  121. if ( m_ElementList.Count() == 0 && m_Actor == NULL_STRING && m_fDisabled == false )
  122. {
  123. AddNewElement( NULL );
  124. }
  125. #endif
  126. }
  127. //-----------------------------------------------------------------------------
  128. bool CAI_ScriptConditions::EvalState( const EvalArgs_t &args )
  129. {
  130. if ( !args.pActor )
  131. return true;
  132. CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
  133. // !!!LATER - fix this code, we shouldn't need the table anymore
  134. // now that we've placed the NPC state defs in a logical order (sjb)
  135. static int stateVals[] =
  136. {
  137. -1, // NPC_STATE_NONE
  138. 0, // NPC_STATE_IDLE
  139. 1, // NPC_STATE_ALERT
  140. 2, // NPC_STATE_COMBAT
  141. -1, // NPC_STATE_SCRIPT
  142. -1, // NPC_STATE_PLAYDEAD
  143. -1, // NPC_STATE_PRONE
  144. -1, // NPC_STATE_DEAD
  145. };
  146. int valState = stateVals[pNpc->m_NPCState];
  147. if ( valState < 0 )
  148. {
  149. if ( pNpc->m_NPCState == NPC_STATE_SCRIPT && m_fScriptStatus >= TRS_TRUE )
  150. return true;
  151. return false;
  152. }
  153. const int valLow = stateVals[m_fMinState];
  154. const int valHigh = stateVals[m_fMaxState];
  155. if ( valLow > valHigh )
  156. {
  157. DevMsg( "Script condition warning: Invalid setting for Maximum/Minimum state\n" );
  158. Disable();
  159. return false;
  160. }
  161. return ( valState >= valLow && valState <= valHigh );
  162. }
  163. //-----------------------------------------------------------------------------
  164. bool CAI_ScriptConditions::EvalActorSeePlayer( const EvalArgs_t &args )
  165. {
  166. if( m_fActorSeePlayer == TRS_NONE )
  167. {
  168. // Don't care, so don't do any work.
  169. return true;
  170. }
  171. if ( !args.pActor )
  172. return true;
  173. bool fCanSeePlayer = args.pActor->MyNPCPointer()->HasCondition( COND_SEE_PLAYER );
  174. return ( (int)m_fActorSeePlayer == (int)fCanSeePlayer );
  175. }
  176. //-----------------------------------------------------------------------------
  177. bool CAI_ScriptConditions::EvalActorSeeTarget( const EvalArgs_t &args )
  178. {
  179. if( m_fActorSeeTarget == TRS_NONE )
  180. {
  181. // Don't care, so don't do any work.
  182. return true;
  183. }
  184. if ( args.pTarget )
  185. {
  186. if ( !args.pActor )
  187. return true;
  188. CAI_BaseNPC *pNPCActor = args.pActor->MyNPCPointer();
  189. #ifdef HL2_EPISODIC
  190. // This is the code we want to have written for HL2, but HL2 shipped without the QuerySeeEntity() call. This #ifdef really wants to be
  191. // something like #ifndef HL2_RETAIL, since this change does want to be in any products that are built henceforth. (sjb)
  192. bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget ) && pNPCActor->QuerySeeEntity( args.pTarget );
  193. #else
  194. bool fSee = pNPCActor->FInViewCone( args.pTarget ) && pNPCActor->FVisible( args.pTarget );
  195. #endif//HL2_EPISODIC
  196. if( fSee )
  197. {
  198. if( m_fActorSeeTarget == TRS_TRUE )
  199. {
  200. return true;
  201. }
  202. return false;
  203. }
  204. else
  205. {
  206. if( m_fActorSeeTarget == TRS_FALSE )
  207. {
  208. return true;
  209. }
  210. return false;
  211. }
  212. }
  213. return true;
  214. }
  215. //-----------------------------------------------------------------------------
  216. bool CAI_ScriptConditions::EvalPlayerActorProximity( const EvalArgs_t &args )
  217. {
  218. return ( !args.pActor || m_PlayerActorProxTester.Check( args.pPlayer, args.pActor ) );
  219. }
  220. //-----------------------------------------------------------------------------
  221. bool CAI_ScriptConditions::EvalPlayerTargetProximity( const EvalArgs_t &args )
  222. {
  223. return ( !args.pTarget ||
  224. m_PlayerTargetProxTester.Check( args.pPlayer, args.pTarget ) );
  225. }
  226. //-----------------------------------------------------------------------------
  227. bool CAI_ScriptConditions::EvalActorTargetProximity( const EvalArgs_t &args )
  228. {
  229. return ( !args.pTarget || !args.pActor ||
  230. m_ActorTargetProxTester.Check( args.pActor, args.pTarget ) );
  231. }
  232. //-----------------------------------------------------------------------------
  233. bool CAI_ScriptConditions::EvalPlayerActorLook( const EvalArgs_t &args )
  234. {
  235. return ( !args.pActor ||
  236. IsInFOV( args.pPlayer, args.pActor, m_flPlayerActorFOV, m_bPlayerActorFOVTrueCone ) );
  237. }
  238. //-----------------------------------------------------------------------------
  239. bool CAI_ScriptConditions::EvalPlayerTargetLook( const EvalArgs_t &args )
  240. {
  241. return ( !args.pTarget || IsInFOV( args.pPlayer, args.pTarget, m_flPlayerTargetFOV, m_bPlayerTargetFOVTrueCone ) );
  242. }
  243. //-----------------------------------------------------------------------------
  244. bool CAI_ScriptConditions::EvalPlayerActorLOS( const EvalArgs_t &args )
  245. {
  246. if( m_fPlayerActorLOS == TRS_NONE )
  247. {
  248. // Don't execute expensive code if we don't care.
  249. return true;
  250. }
  251. return ( !args.pActor || PlayerHasLineOfSight( args.pPlayer, args.pActor, m_fPlayerActorLOS == TRS_FALSE ) );
  252. }
  253. //-----------------------------------------------------------------------------
  254. bool CAI_ScriptConditions::EvalPlayerTargetLOS( const EvalArgs_t &args )
  255. {
  256. if( m_fPlayerTargetLOS == TRS_NONE )
  257. {
  258. // Don't execute expensive code if we don't care.
  259. return true;
  260. }
  261. return ( !args.pTarget || PlayerHasLineOfSight( args.pPlayer, args.pTarget, m_fPlayerTargetLOS == TRS_FALSE ) );
  262. }
  263. bool CAI_ScriptConditions::EvalActorInPVS( const EvalArgs_t &args )
  264. {
  265. if( m_fActorInPVS == TRS_NONE )
  266. {
  267. // Don't execute expensive code if we don't care.
  268. return true;
  269. }
  270. return ( !args.pActor || ActorInPlayersPVS( args.pActor, m_fActorInPVS == TRS_FALSE ) );
  271. }
  272. //-----------------------------------------------------------------------------
  273. bool CAI_ScriptConditions::EvalPlayerBlockingActor( const EvalArgs_t &args )
  274. {
  275. if ( m_fPlayerBlockingActor == TRS_NONE )
  276. return true;
  277. #if 0
  278. CAI_BaseNPC *pNpc = args.pActor->MyNPCPointer();
  279. const float testDist = 30.0;
  280. Vector origin = args.pActor->WorldSpaceCenter();
  281. Vector delta = UTIL_YawToVector( args.pActor->GetAngles().y ) * testDist;
  282. Vector vecAbsMins, vecAbsMaxs;
  283. args.pActor->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
  284. bool intersect = IsBoxIntersectingRay( vecAbsMins, vecAbsMaxs, origin, delta );
  285. #endif
  286. if ( m_fPlayerBlockingActor == TRS_FALSE )
  287. return true;
  288. return false; // for now, never say player is blocking
  289. }
  290. //-----------------------------------------------------------------------------
  291. bool CAI_ScriptConditions::EvalPlayerInVehicle( const EvalArgs_t &args )
  292. {
  293. // We don't care
  294. if ( m_fPlayerInVehicle == TRS_NONE )
  295. return true;
  296. // Need a player to test
  297. if ( args.pPlayer == NULL )
  298. return false;
  299. // Desired states must match
  300. return ( !!args.pPlayer->IsInAVehicle() == m_fPlayerInVehicle );
  301. }
  302. //-----------------------------------------------------------------------------
  303. bool CAI_ScriptConditions::EvalActorInVehicle( const EvalArgs_t &args )
  304. {
  305. // We don't care
  306. if ( m_fActorInVehicle == TRS_NONE )
  307. return true;
  308. if ( !args.pActor )
  309. return true;
  310. // Must be able to be in a vehicle at all
  311. CBaseCombatCharacter *pBCC = args.pActor->MyCombatCharacterPointer();
  312. if ( pBCC == NULL )
  313. return false;
  314. // Desired states must match
  315. return ( !!pBCC->IsInAVehicle() == m_fActorInVehicle );
  316. }
  317. //-----------------------------------------------------------------------------
  318. void CAI_ScriptConditions::Spawn()
  319. {
  320. Assert( ( m_fMinState == NPC_STATE_IDLE || m_fMinState == NPC_STATE_COMBAT || m_fMinState == NPC_STATE_ALERT ) &&
  321. ( m_fMaxState == NPC_STATE_IDLE || m_fMaxState == NPC_STATE_COMBAT || m_fMaxState == NPC_STATE_ALERT ) );
  322. m_PlayerActorProxTester.Init( m_flPlayerActorProximity );
  323. m_PlayerTargetProxTester.Init( m_flPlayerTargetProximity );
  324. m_ActorTargetProxTester.Init( m_flActorTargetProximity );
  325. m_bLeaveAsleep = m_fDisabled;
  326. }
  327. //-----------------------------------------------------------------------------
  328. void CAI_ScriptConditions::Activate()
  329. {
  330. BaseClass::Activate();
  331. // When we spawn, m_fDisabled is initial state as given by worldcraft.
  332. // following that, we keep it updated and it reflects current state.
  333. if( !m_fDisabled )
  334. Enable();
  335. #ifdef HL2_EPISODIC
  336. gEntList.AddListenerEntity( this );
  337. #endif
  338. }
  339. //-----------------------------------------------------------------------------
  340. void CAI_ScriptConditions::UpdateOnRemove( void )
  341. {
  342. gEntList.RemoveListenerEntity( this );
  343. BaseClass::UpdateOnRemove();
  344. m_ElementList.Purge();
  345. }
  346. //-----------------------------------------------------------------------------
  347. void CAI_ScriptConditions::EvaluationThink()
  348. {
  349. if ( m_fDisabled == true )
  350. return;
  351. int iActorsDone = 0;
  352. #ifdef HL2_DLL
  353. if( AI_GetSinglePlayer()->GetFlags() & FL_NOTARGET )
  354. {
  355. ScrCondDbgMsg( ("%s WARNING: Player is NOTARGET. This will affect all LOS conditiosn involving the player!\n", GetDebugName()) );
  356. }
  357. #endif
  358. for ( int i = 0; i < m_ElementList.Count(); )
  359. {
  360. CAI_ScriptConditionsElement *pConditionElement = &m_ElementList[i];
  361. if ( pConditionElement == NULL )
  362. {
  363. i++;
  364. continue;
  365. }
  366. CBaseEntity *pActor = pConditionElement->GetActor();
  367. CBaseEntity *pActivator = this;
  368. #ifdef HL2_EPISODIC
  369. if ( pActor && HasSpawnFlags( SF_ACTOR_AS_ACTIVATOR ) )
  370. {
  371. pActivator = pActor;
  372. }
  373. #endif
  374. AssertMsg( !m_fDisabled, ("Violated invariant between CAI_ScriptConditions disabled state and think func setting") );
  375. if ( m_Actor != NULL_STRING && !pActor )
  376. {
  377. if ( m_ElementList.Count() == 1 )
  378. {
  379. DevMsg( "Warning: Active AI script conditions associated with an non-existant or destroyed NPC\n" );
  380. m_NoValidActors.FireOutput( this, this, 0 );
  381. }
  382. iActorsDone++;
  383. m_ElementList.Remove( i );
  384. continue;
  385. }
  386. i++;
  387. if( m_flMinTimeout > 0 && pConditionElement->GetTimeOut()->Expired() )
  388. {
  389. ScrCondDbgMsg( ( "%s firing output OnConditionsTimeout (%f seconds)\n", STRING( GetEntityName() ), pConditionElement->GetTimeOut()->GetInterval() ) );
  390. iActorsDone++;
  391. m_OnConditionsTimeout.FireOutput( pActivator, this );
  392. continue;
  393. }
  394. bool result = true;
  395. const int nEvaluators = sizeof( gm_Evaluators ) / sizeof( gm_Evaluators[0] );
  396. EvalArgs_t args =
  397. {
  398. pActor,
  399. GetPlayer(),
  400. m_hTarget.Get()
  401. };
  402. for ( int i = 0; i < nEvaluators; ++i )
  403. {
  404. if ( !(this->*gm_Evaluators[i].pfnEvaluator)( args ) )
  405. {
  406. pConditionElement->GetTimer()->Reset();
  407. result = false;
  408. ScrCondDbgMsg( ( "%s failed on: %s\n", GetDebugName(), gm_Evaluators[ i ].pszName ) );
  409. break;
  410. }
  411. }
  412. if ( result )
  413. {
  414. ScrCondDbgMsg( ( "%s waiting... %f\n", GetDebugName(), pConditionElement->GetTimer()->GetRemaining() ) );
  415. }
  416. if ( result && pConditionElement->GetTimer()->Expired() )
  417. {
  418. ScrCondDbgMsg( ( "%s firing output OnConditionsSatisfied\n", GetDebugName() ) );
  419. // Default behavior for now, provide worldcraft option later.
  420. iActorsDone++;
  421. m_OnConditionsSatisfied.FireOutput( pActivator, this );
  422. }
  423. }
  424. //All done!
  425. if ( iActorsDone == m_ElementList.Count() )
  426. {
  427. Disable();
  428. m_ElementList.Purge();
  429. }
  430. SetThinkTime();
  431. }
  432. //-----------------------------------------------------------------------------
  433. int CAI_ScriptConditions::AddNewElement( CBaseEntity *pActor )
  434. {
  435. CAI_ScriptConditionsElement conditionelement;
  436. conditionelement.SetActor( pActor );
  437. if( m_flMaxTimeout > 0 )
  438. {
  439. conditionelement.GetTimeOut()->Set( random->RandomFloat( m_flMinTimeout, m_flMaxTimeout ), false );
  440. }
  441. else
  442. {
  443. conditionelement.GetTimeOut()->Set( m_flMinTimeout, false );
  444. }
  445. conditionelement.GetTimer()->Set( m_flRequiredTime );
  446. if ( m_flRequiredTime > 0 )
  447. {
  448. conditionelement.GetTimer()->Reset();
  449. }
  450. return m_ElementList.AddToTail( conditionelement );
  451. }
  452. //-----------------------------------------------------------------------------
  453. void CAI_ScriptConditions::Enable( void )
  454. {
  455. m_hTarget = gEntList.FindEntityByName( NULL, m_target );
  456. CBaseEntity *pActor = gEntList.FindEntityByName( NULL, m_Actor );
  457. if ( m_ElementList.Count() == 0 )
  458. {
  459. if ( m_Actor != NULL_STRING && pActor == NULL )
  460. {
  461. DevMsg( "Warning: Spawning AI script conditions (%s) associated with an non-existant NPC\n", GetDebugName() );
  462. m_NoValidActors.FireOutput( this, this, 0 );
  463. Disable();
  464. return;
  465. }
  466. if ( pActor && pActor->MyNPCPointer() == NULL )
  467. {
  468. Warning( "Script condition warning: warning actor is not an NPC\n" );
  469. Disable();
  470. return;
  471. }
  472. }
  473. while( pActor != NULL )
  474. {
  475. if( !ActorInList(pActor) )
  476. {
  477. AddNewElement( pActor );
  478. }
  479. pActor = gEntList.FindEntityByName( pActor, m_Actor );
  480. }
  481. //If we are hitting this it means we are using a Target->Player condition
  482. if ( m_Actor == NULL_STRING )
  483. {
  484. if( !ActorInList(pActor) )
  485. {
  486. AddNewElement( NULL );
  487. }
  488. }
  489. m_fDisabled = false;
  490. SetThink( &CAI_ScriptConditions::EvaluationThink );
  491. SetThinkTime();
  492. }
  493. //-----------------------------------------------------------------------------
  494. void CAI_ScriptConditions::Disable( void )
  495. {
  496. SetThink( NULL );
  497. m_fDisabled = true;
  498. }
  499. //-----------------------------------------------------------------------------
  500. void CAI_ScriptConditions::InputEnable( inputdata_t &inputdata )
  501. {
  502. m_bLeaveAsleep = false;
  503. Enable();
  504. }
  505. //-----------------------------------------------------------------------------
  506. void CAI_ScriptConditions::InputDisable( inputdata_t &inputdata )
  507. {
  508. m_bLeaveAsleep = true;
  509. Disable();
  510. }
  511. //-----------------------------------------------------------------------------
  512. bool CAI_ScriptConditions::IsInFOV( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone )
  513. {
  514. CBaseCombatCharacter *pCombatantViewer = (pViewer) ? pViewer->MyCombatCharacterPointer() : NULL;
  515. if ( fov < 360 && pCombatantViewer /*&& pViewed*/ )
  516. {
  517. Vector vLookDir;
  518. Vector vActorDir;
  519. // Halve the fov. As expressed here, fov is the full size of the viewcone.
  520. float flFovDotResult;
  521. flFovDotResult = cos( DEG2RAD( fov / 2 ) );
  522. float fDotPr = 1;
  523. if( bTrueCone )
  524. {
  525. // 3D Check
  526. vLookDir = pCombatantViewer->EyeDirection3D( );
  527. vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
  528. vActorDir.NormalizeInPlace();
  529. fDotPr = vLookDir.Dot(vActorDir);
  530. }
  531. else
  532. {
  533. // 2D Check
  534. vLookDir = pCombatantViewer->EyeDirection2D( );
  535. vActorDir = pViewed->EyePosition() - pViewer->EyePosition();
  536. vActorDir.z = 0.0;
  537. vActorDir.AsVector2D().NormalizeInPlace();
  538. fDotPr = vLookDir.AsVector2D().Dot(vActorDir.AsVector2D());
  539. }
  540. if ( fDotPr < flFovDotResult )
  541. {
  542. if( fov < 0 )
  543. {
  544. // Designer has requested that the player
  545. // NOT be looking at this place.
  546. return true;
  547. }
  548. return false;
  549. }
  550. }
  551. if( fov < 0 )
  552. {
  553. return false;
  554. }
  555. return true;
  556. }
  557. //-----------------------------------------------------------------------------
  558. bool CAI_ScriptConditions::PlayerHasLineOfSight( CBaseEntity *pViewer, CBaseEntity *pViewed, bool fNot )
  559. {
  560. CBaseCombatCharacter *pCombatantViewer = pViewer->MyCombatCharacterPointer();
  561. if( pCombatantViewer )
  562. {
  563. // We always trace towards the player, so we handle players-in-vehicles
  564. if ( pViewed->FVisible( pCombatantViewer ) )
  565. {
  566. // Line of sight exists.
  567. if( fNot )
  568. {
  569. return false;
  570. }
  571. else
  572. {
  573. return true;
  574. }
  575. }
  576. else
  577. {
  578. // No line of sight.
  579. if( fNot )
  580. {
  581. return true;
  582. }
  583. else
  584. {
  585. return false;
  586. }
  587. }
  588. }
  589. return true;
  590. }
  591. //-----------------------------------------------------------------------------
  592. bool CAI_ScriptConditions::ActorInPlayersPVS( CBaseEntity *pActor, bool bNot )
  593. {
  594. if ( pActor == NULL )
  595. return true;
  596. bool bInPVS = !!UTIL_FindClientInPVS( pActor->edict());
  597. if ( bInPVS )
  598. {
  599. if( bNot )
  600. {
  601. return false;
  602. }
  603. else
  604. {
  605. return true;
  606. }
  607. }
  608. else
  609. {
  610. if( bNot )
  611. {
  612. return true;
  613. }
  614. else
  615. {
  616. return false;
  617. }
  618. }
  619. }
  620. //-----------------------------------------------------------------------------
  621. bool CAI_ScriptConditions::ActorInList( CBaseEntity *pActor )
  622. {
  623. for ( int i = 0; i < m_ElementList.Count(); i++ )
  624. {
  625. if ( m_ElementList[i].GetActor() == pActor )
  626. return true;
  627. }
  628. return false;
  629. }
  630. //-----------------------------------------------------------------------------
  631. void CAI_ScriptConditions::OnEntitySpawned( CBaseEntity *pEntity )
  632. {
  633. if( m_fDisabled && m_bLeaveAsleep )
  634. {
  635. // Don't add elements if we're not currently running and don't want to automatically wake up.
  636. // Any spawning NPC's we miss during this time will be found and added when manually Enabled().
  637. return;
  638. }
  639. if ( pEntity->MyNPCPointer() == NULL )
  640. return;
  641. if ( pEntity->NameMatches( m_Actor ) )
  642. {
  643. if ( ActorInList( pEntity ) == false )
  644. {
  645. AddNewElement( pEntity );
  646. if ( m_fDisabled == true && m_bLeaveAsleep == false )
  647. {
  648. Enable();
  649. }
  650. }
  651. }
  652. }
  653. //=============================================================================