Counter Strike : Global Offensive Source Code
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.

855 lines
21 KiB

  1. //========== Copyright � 2008, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "ai_behavior_fightfromcover.h"
  8. #include "ai_hint.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. //-----------------------------------------------------------------------------
  12. //
  13. //-----------------------------------------------------------------------------
  14. BEGIN_DATADESC( CAI_FightFromCoverBehavior )
  15. DEFINE_FIELD( m_hGoal, FIELD_EHANDLE ),
  16. DEFINE_EMBEDDED( m_FrontMoveMonitor ),
  17. DEFINE_EMBEDDED( m_FrontTimer ),
  18. END_DATADESC();
  19. //-----------------------------------------------------------------------------
  20. //
  21. //-----------------------------------------------------------------------------
  22. CAI_FightFromCoverBehavior::CAI_FightFromCoverBehavior()
  23. {
  24. }
  25. //-----------------------------------------------------------------------------
  26. //
  27. //-----------------------------------------------------------------------------
  28. void CAI_FightFromCoverBehavior::SetGoal( CAI_FightFromCoverGoal *pGoal )
  29. {
  30. m_hGoal = pGoal;
  31. }
  32. //-----------------------------------------------------------------------------
  33. //
  34. //-----------------------------------------------------------------------------
  35. void CAI_FightFromCoverBehavior::ClearGoal()
  36. {
  37. m_hGoal = NULL;
  38. }
  39. //-----------------------------------------------------------------------------
  40. //
  41. //-----------------------------------------------------------------------------
  42. bool CAI_FightFromCoverBehavior::IsPointInZone( const Vector &v )
  43. {
  44. if ( !m_hGoal->GetFrontDirection().IsValid() )
  45. {
  46. return true;
  47. }
  48. Vector vCenterZone;
  49. vCenterZone = ( m_hGoal->GetFrontDirection() * -m_hGoal->m_BiasZone ) + m_hGoal->GetFrontPosition();
  50. Vector vRelativePos ;
  51. VectorRotate( v - vCenterZone, -m_hGoal->GetFrontAngles(), vRelativePos );
  52. float w = m_hGoal->m_WidthZone * .5, l = m_hGoal->m_LengthZone * .5, h = m_hGoal->m_HeightZone * .5;
  53. Vector mins( -l, -w, -h ), maxs( l, w, h );
  54. if ( vRelativePos.x < mins.x || vRelativePos.x > maxs.x ||
  55. vRelativePos.y < mins.y || vRelativePos.y > maxs.y ||
  56. vRelativePos.z < mins.z || vRelativePos.z > maxs.z )
  57. {
  58. // NDebugOverlay::Cross3D( v, 36, 255, 0, 0, true, 3 );
  59. return false;
  60. }
  61. // NDebugOverlay::Cross3D( v, 36, 0, 255, 0, true, 3 );
  62. return true;
  63. }
  64. //-----------------------------------------------------------------------------
  65. //
  66. //-----------------------------------------------------------------------------
  67. bool CAI_FightFromCoverBehavior::FValidateHintType ( CAI_Hint *pHint )
  68. {
  69. if ( pHint->HintType() == HINT_GENERIC && pHint->GetGenericType() == m_hGoal->m_GenericHintType )
  70. {
  71. return true;
  72. }
  73. return BaseClass::FValidateHintType( pHint );
  74. }
  75. //-----------------------------------------------------------------------------
  76. //
  77. //-----------------------------------------------------------------------------
  78. bool CAI_FightFromCoverBehavior::HintSearchFilter( void *pContext, CAI_Hint *pCandidate )
  79. {
  80. CAI_FightFromCoverBehavior *pThis = (CAI_FightFromCoverBehavior *)pContext;
  81. Vector vHintDir;
  82. if ( pThis->m_hGoal->GetFrontDirection().IsValid() )
  83. {
  84. pCandidate->GetVectors( &vHintDir, NULL, NULL );
  85. if ( vHintDir.Dot( pThis->m_hGoal->GetFrontDirection() ) < DOT_45DEGREE )
  86. {
  87. return false;
  88. }
  89. }
  90. return pThis->IsPointInZone( pCandidate->GetAbsOrigin() );
  91. }
  92. //-----------------------------------------------------------------------------
  93. //
  94. //-----------------------------------------------------------------------------
  95. void CAI_FightFromCoverBehavior::GatherConditions()
  96. {
  97. BaseClass::GatherConditions();
  98. ClearCondition( COND_FFC_HINT_CHANGE );
  99. if ( !m_hGoal )
  100. {
  101. SetCondition( COND_FFC_HINT_CHANGE );
  102. ClearHintNode();
  103. return;
  104. }
  105. if ( GetHintNode() && m_FrontTimer.Expired() && m_FrontMoveMonitor.TargetMoved( m_hGoal->GetFrontPosition() ) )
  106. {
  107. float flFastRejectDist = MAX( m_hGoal->m_WidthZone, m_hGoal->m_LengthZone ) + m_hGoal->m_BiasZone;
  108. if ( ( GetHintNode()->GetAbsOrigin() - m_hGoal->GetFrontPosition() ).LengthSqr() > Square( flFastRejectDist ) || !IsPointInZone( GetHintNode()->GetAbsOrigin() ) )
  109. {
  110. GetHintNode()->Unlock();
  111. SetHintNode( NULL );
  112. SetCondition( COND_FFC_HINT_CHANGE );
  113. }
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. //
  118. //-----------------------------------------------------------------------------
  119. bool CAI_FightFromCoverBehavior::CanSelectSchedule()
  120. {
  121. return ( m_hGoal != NULL );
  122. }
  123. //-----------------------------------------------------------------------------
  124. //
  125. //-----------------------------------------------------------------------------
  126. int CAI_FightFromCoverBehavior::SelectSchedule()
  127. {
  128. Assert( m_hGoal != NULL );
  129. if ( !m_hGoal )
  130. {
  131. return BaseClass::SelectSchedule();
  132. }
  133. if ( !GetHintNode() )
  134. {
  135. if ( m_FrontTimer.Expired() )
  136. {
  137. m_FrontTimer.Set( .75, 1.5 );
  138. Vector vFront = m_hGoal->GetFrontPosition();
  139. CHintCriteria hintCriteria;
  140. hintCriteria.SetHintType( HINT_GENERIC );
  141. hintCriteria.SetGenericType( m_hGoal->m_GenericHintType );
  142. hintCriteria.SetFlag( bits_HINT_NODE_NEAREST | bits_HINT_NODE_USE_GROUP );
  143. // Add the search position
  144. hintCriteria.AddIncludePosition( vFront, MAX( m_hGoal->m_WidthZone, m_hGoal->m_LengthZone ) + m_hGoal->m_BiasZone );
  145. hintCriteria.AddExcludePosition( m_hGoal->GetGoalEntity()->GetAbsOrigin(), 2.5*12 );
  146. hintCriteria.SetFilterFunc( &HintSearchFilter, this );
  147. const Vector &vDir = m_hGoal->GetFrontDirection();
  148. if ( vDir.IsValid() )
  149. {
  150. vFront += vDir * m_hGoal->m_LengthZone;
  151. }
  152. CAI_Hint *pHint = CAI_HintManager::FindHint( GetOuter(), vFront, hintCriteria );
  153. if ( !pHint )
  154. {
  155. // @HACKHACK [5/21/2008 tom]
  156. float lengthSaved = m_hGoal->m_LengthZone, biasSaved = m_hGoal->m_BiasZone, widthSaved = m_hGoal->m_WidthZone;
  157. m_hGoal->m_LengthZone += 2000;
  158. m_hGoal->m_BiasZone += 1000;
  159. m_hGoal->m_WidthZone += 2000;
  160. pHint = CAI_HintManager::FindHint( GetOuter(), vFront, hintCriteria );
  161. m_hGoal->m_LengthZone = lengthSaved;
  162. m_hGoal->m_BiasZone = biasSaved;
  163. m_hGoal->m_WidthZone = widthSaved;
  164. }
  165. if ( pHint )
  166. {
  167. SetHintNode( pHint );
  168. pHint->Lock( GetOuter() );
  169. m_FrontMoveMonitor.SetMark( vFront, 3*12 );
  170. }
  171. }
  172. }
  173. if ( GetHintNode() )
  174. {
  175. if ( ( GetHintNode()->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr() > Square( 12.0 ) )
  176. {
  177. return SCHED_FFC_RUN_TO_HINT;
  178. }
  179. else if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && !GetOuter()->GetShotRegulator()->IsInRestInterval() )
  180. {
  181. return SCHED_FFC_ATTACK;
  182. }
  183. else if ( HasCondition( COND_NO_PRIMARY_AMMO ) )
  184. {
  185. return SCHED_RELOAD;
  186. }
  187. else
  188. {
  189. GetOuter()->GetShotRegulator()->Reset( true );
  190. return SCHED_FFC_HOLD_COVER;
  191. }
  192. }
  193. return BaseClass::SelectSchedule();
  194. }
  195. //-----------------------------------------------------------------------------
  196. //
  197. //-----------------------------------------------------------------------------
  198. void CAI_FightFromCoverBehavior::StartTask( const Task_t *pTask )
  199. {
  200. switch ( pTask->iTask )
  201. {
  202. case TASK_FFC_GET_PATH_TO_HINT:
  203. {
  204. ChainStartTask( TASK_GET_PATH_TO_HINTNODE );
  205. if ( !HasCondition(COND_TASK_FAILED) )
  206. {
  207. UpdateAnimationsFromHint();
  208. }
  209. else
  210. {
  211. // Should mark hint and try to find another one
  212. ClearHintNode( 5 );
  213. }
  214. break;
  215. }
  216. case TASK_FFC_ATTACK:
  217. {
  218. CBaseCombatWeapon *pWeapon = GetOuter()->GetActiveWeapon();
  219. if ( !pWeapon )
  220. {
  221. TaskFail( "No weapon" );
  222. return;
  223. }
  224. int clipSize = pWeapon->GetMaxClip1();
  225. GetOuter()->GetShotRegulator()->SetBurstShotCountRange( clipSize * .3, clipSize * .6 );
  226. GetOuter()->GetShotRegulator()->SetRestInterval( INT_MAX, INT_MAX );
  227. GetOuter()->GetShotRegulator()->Reset();
  228. StartAnimationTask( m_ShootAnim, true, ACT_RANGE_ATTACK1 );
  229. GetOuter()->SetLastAttackTime( gpGlobals->curtime );
  230. GetOuter()->OnRangeAttack1();
  231. break;
  232. }
  233. case TASK_RELOAD:
  234. {
  235. if ( !StartAnimationTask( m_ReloadAnim, true ) )
  236. {
  237. BaseClass::StartTask( pTask );
  238. }
  239. break;
  240. }
  241. case TASK_FFC_PEEK:
  242. {
  243. StartAnimationTask( m_PeekAnim );
  244. break;
  245. }
  246. case TASK_FFC_COVER:
  247. {
  248. StartAnimationTask( m_CoverAnim );
  249. break;
  250. }
  251. default:
  252. BaseClass::StartTask( pTask );
  253. }
  254. }
  255. //-----------------------------------------------------------------------------
  256. //
  257. //-----------------------------------------------------------------------------
  258. void CAI_FightFromCoverBehavior::RunTask( const Task_t *pTask )
  259. {
  260. switch ( pTask->iTask )
  261. {
  262. case TASK_FFC_ATTACK:
  263. {
  264. GetOuter()->AutoMovement( );
  265. if ( GetOuter()->IsActivityFinished() )
  266. {
  267. if ( !GetEnemy() || !GetEnemy()->IsAlive() )
  268. {
  269. TaskComplete();
  270. return;
  271. }
  272. if ( !GetOuter()->GetShotRegulator()->IsInRestInterval() )
  273. {
  274. if ( GetOuter()->GetShotRegulator()->ShouldShoot() )
  275. {
  276. GetOuter()->OnRangeAttack1();
  277. StartAnimationTask( m_ShootAnim, true, ACT_RANGE_ATTACK1 );
  278. }
  279. return;
  280. }
  281. TaskComplete();
  282. }
  283. break;
  284. }
  285. case TASK_FFC_PEEK:
  286. case TASK_FFC_COVER:
  287. {
  288. ChainRunTask( TASK_PLAY_SEQUENCE );
  289. break;
  290. }
  291. default:
  292. BaseClass::RunTask( pTask);
  293. }
  294. }
  295. //-----------------------------------------------------------------------------
  296. //
  297. //-----------------------------------------------------------------------------
  298. void CAI_FightFromCoverBehavior::OnUpdateShotRegulator()
  299. {
  300. }
  301. //-----------------------------------------------------------------------------
  302. //
  303. //-----------------------------------------------------------------------------
  304. void CAI_FightFromCoverBehavior::UpdateAnimationsFromHint()
  305. {
  306. m_EntryAnim.Reset();
  307. m_MoveAnim.Reset();
  308. m_CoverAnim.Reset();
  309. m_ReloadAnim.Reset();
  310. m_PeekAnim.Reset();
  311. m_ShootAnim.Reset();
  312. m_ExitAnim.Reset();
  313. if ( !GetHintNode() )
  314. {
  315. return;
  316. }
  317. CScriptScope &hintScope = GetHintNode()->m_ScriptScope;
  318. ScriptVariant_t animationsVar;
  319. if ( hintScope.GetValue( "animations", &animationsVar ) )
  320. {
  321. if ( animationsVar.m_type == FIELD_HSCRIPT )
  322. {
  323. CScriptScope animations;
  324. ScriptVariant_t var;
  325. animations.Init( animationsVar.m_hScript );
  326. GetAnimation( animations, "movement", &m_MoveAnim );
  327. GetAnimation( animations, "entry", &m_EntryAnim );
  328. if ( m_EntryAnim.id != ACT_INVALID )
  329. {
  330. DevMsg( "entry anim not yet supported!\n" );
  331. m_EntryAnim.Reset();
  332. }
  333. GetAnimation( animations, "cover", &m_CoverAnim );
  334. GetAnimation( animations, "reload", &m_ReloadAnim );
  335. GetAnimation( animations, "peek", &m_PeekAnim );
  336. GetAnimation( animations, "shoot", &m_ShootAnim );
  337. GetAnimation( animations, "exit", &m_ExitAnim );
  338. if ( m_EntryAnim.id != ACT_INVALID )
  339. {
  340. DevMsg( "exit anim not yet supported!\n" );
  341. m_EntryAnim.Reset();
  342. }
  343. }
  344. else
  345. {
  346. DevMsg( "Unexpected type for script value \"animations\"\n" );
  347. }
  348. hintScope.ReleaseValue( animationsVar );
  349. }
  350. if ( m_MoveAnim.id != ACT_INVALID )
  351. {
  352. if ( m_MoveAnim.bActivity )
  353. {
  354. GetNavigator()->SetMovementActivity( (Activity)m_MoveAnim.id );
  355. }
  356. else
  357. {
  358. GetNavigator()->SetMovementSequence( m_MoveAnim.id );
  359. }
  360. }
  361. else
  362. {
  363. ChainStartTask( TASK_RUN_PATH );
  364. }
  365. if ( m_EntryAnim.id != ACT_INVALID )
  366. {
  367. Assert( 0 );
  368. }
  369. else if ( m_CoverAnim.id != ACT_INVALID )
  370. {
  371. if ( m_CoverAnim.bActivity )
  372. {
  373. GetNavigator()->SetArrivalActivity( (Activity)m_CoverAnim.id );
  374. }
  375. else
  376. {
  377. GetNavigator()->SetArrivalSequence( m_CoverAnim.id );
  378. }
  379. }
  380. }
  381. //-----------------------------------------------------------------------------
  382. //
  383. //-----------------------------------------------------------------------------
  384. bool CAI_FightFromCoverBehavior::GetAnimation( CScriptScope &scope, const char *pszKey, Animation_t *pAnimation )
  385. {
  386. ScriptVariant_t var;
  387. bool result = false;
  388. // Find the movement activity or sequence
  389. if ( scope.GetValue( pszKey, &var ) )
  390. {
  391. if ( var.m_type == FIELD_CSTRING )
  392. {
  393. pAnimation->bActivity = StringHasPrefixCaseSensitive( var, "ACT_" );
  394. if ( !pAnimation->bActivity )
  395. {
  396. pAnimation->id = GetOuter()->LookupSequence( var );
  397. if ( pAnimation->id < 0 )
  398. {
  399. pAnimation->Reset();
  400. }
  401. }
  402. else
  403. {
  404. pAnimation->id = CAI_BaseNPC::GetActivityID( var );
  405. }
  406. if ( pAnimation->id == ACT_INVALID )
  407. {
  408. DevMsg( "Failed to resolve animation \"%s\"\n", var.m_pszString );
  409. }
  410. }
  411. scope.ReleaseValue( var );
  412. }
  413. return result;
  414. }
  415. //-----------------------------------------------------------------------------
  416. //
  417. //-----------------------------------------------------------------------------
  418. bool CAI_FightFromCoverBehavior::StartAnimationTask( const Animation_t &animation, bool bReset, Activity defaultActivity )
  419. {
  420. if ( animation.id != ACT_INVALID )
  421. {
  422. if ( animation.bActivity )
  423. {
  424. if ( bReset )
  425. GetOuter()->ResetIdealActivity( (Activity)animation.id );
  426. else
  427. GetOuter()->SetIdealActivity( (Activity)animation.id );
  428. }
  429. else
  430. {
  431. GetOuter()->SetIdealSequence( animation.id, bReset );
  432. }
  433. return true;
  434. }
  435. else
  436. {
  437. if ( bReset )
  438. GetOuter()->SetIdealActivity( defaultActivity );
  439. return false;
  440. }
  441. }
  442. //-----------------------------------------------------------------------------
  443. AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_FightFromCoverBehavior )
  444. DECLARE_CONDITION( COND_FFC_HINT_CHANGE )
  445. DECLARE_TASK( TASK_FFC_GET_PATH_TO_HINT )
  446. DECLARE_TASK( TASK_FFC_COVER )
  447. DECLARE_TASK( TASK_FFC_PEEK )
  448. DECLARE_TASK( TASK_FFC_ATTACK )
  449. //---------------------------------
  450. DEFINE_SCHEDULE
  451. (
  452. SCHED_FFC_RUN_TO_HINT,
  453. " Tasks"
  454. " TASK_FFC_GET_PATH_TO_HINT 0"
  455. " TASK_WAIT_FOR_MOVEMENT 0"
  456. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_COVER"
  457. ""
  458. " Interrupts"
  459. " COND_FFC_HINT_CHANGE"
  460. )
  461. DEFINE_SCHEDULE
  462. (
  463. SCHED_FFC_HOLD_COVER,
  464. " Tasks"
  465. // " TASK_FACE_HINTNODE 0"
  466. " TASK_FFC_COVER 0"
  467. " TASK_WAIT_RANDOM 2.0"
  468. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_PEEK"
  469. ""
  470. " Interrupts"
  471. " COND_FFC_HINT_CHANGE"
  472. " COND_NO_PRIMARY_AMMO"
  473. )
  474. DEFINE_SCHEDULE
  475. (
  476. SCHED_FFC_RELOAD,
  477. " Tasks"
  478. " TASK_RELOAD 0"
  479. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_PEEK"
  480. ""
  481. " Interrupts"
  482. )
  483. DEFINE_SCHEDULE
  484. (
  485. SCHED_FFC_PEEK,
  486. " Tasks"
  487. " TASK_FFC_PEEK 0"
  488. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_PEEK"
  489. ""
  490. " Interrupts"
  491. " COND_NEW_ENEMY"
  492. " COND_CAN_RANGE_ATTACK1"
  493. " COND_FFC_HINT_CHANGE"
  494. )
  495. DEFINE_SCHEDULE
  496. (
  497. SCHED_FFC_HOLD_PEEK,
  498. " Tasks"
  499. " TASK_WAIT_RANDOM 1.0"
  500. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_COVER"
  501. ""
  502. " Interrupts"
  503. " COND_FFC_HINT_CHANGE"
  504. " COND_NEW_ENEMY"
  505. " COND_CAN_RANGE_ATTACK1"
  506. " COND_NO_PRIMARY_AMMO"
  507. )
  508. DEFINE_SCHEDULE
  509. (
  510. SCHED_FFC_ATTACK,
  511. " Tasks"
  512. " TASK_STOP_MOVING 0"
  513. " TASK_FFC_ATTACK 0"
  514. ""
  515. " Interrupts"
  516. " COND_NEW_ENEMY"
  517. " COND_ENEMY_DEAD"
  518. " COND_LIGHT_DAMAGE"
  519. " COND_HEAVY_DAMAGE"
  520. " COND_ENEMY_OCCLUDED"
  521. " COND_NO_PRIMARY_AMMO"
  522. " COND_HEAR_DANGER"
  523. " COND_WEAPON_BLOCKED_BY_FRIEND"
  524. " COND_WEAPON_SIGHT_OCCLUDED"
  525. )
  526. AI_END_CUSTOM_SCHEDULE_PROVIDER()
  527. //-----------------------------------------------------------------------------
  528. //
  529. // CAI_FightFromCoverGoal
  530. //
  531. //-----------------------------------------------------------------------------
  532. BEGIN_DATADESC( CAI_FightFromCoverGoal )
  533. DEFINE_KEYFIELD( m_DirectionalMarker, FIELD_STRING, "DirectionalMarker" ),
  534. DEFINE_KEYFIELD( m_GenericHintType, FIELD_STRING, "GenericHintType" ),
  535. DEFINE_KEYFIELD( m_WidthZone, FIELD_FLOAT, "width" ),
  536. DEFINE_KEYFIELD( m_LengthZone, FIELD_FLOAT, "length" ),
  537. DEFINE_KEYFIELD( m_HeightZone, FIELD_FLOAT, "height" ),
  538. DEFINE_KEYFIELD( m_BiasZone, FIELD_FLOAT, "bias" ),
  539. DEFINE_FIELD( m_vFront, FIELD_POSITION_VECTOR ),
  540. DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetDirectionalMarker", InputSetDirectionalMarker ),
  541. DEFINE_THINKFUNC( FrontThink ),
  542. END_DATADESC()
  543. //-------------------------------------
  544. LINK_ENTITY_TO_CLASS( ai_goal_fightfromcover, CAI_FightFromCoverGoal );
  545. //-------------------------------------
  546. CAI_FightFromCoverGoal::CAI_FightFromCoverGoal()
  547. {
  548. m_vDir.Invalidate();
  549. m_WidthZone = 50*12;
  550. m_LengthZone = 40*12;
  551. m_BiasZone = 5*12;
  552. m_HeightZone = 200*12;
  553. }
  554. //-------------------------------------
  555. const Vector &CAI_FightFromCoverGoal::GetFrontPosition()
  556. {
  557. if ( m_hDirectionalMarker != NULL )
  558. {
  559. return m_vFront;
  560. }
  561. else if ( m_hGoalEntity != NULL )
  562. {
  563. return m_hGoalEntity->GetAbsOrigin();
  564. }
  565. return GetAbsOrigin();
  566. }
  567. //-------------------------------------
  568. const Vector &CAI_FightFromCoverGoal::GetFrontDirection()
  569. {
  570. return m_vDir;
  571. }
  572. //-------------------------------------
  573. const QAngle &CAI_FightFromCoverGoal::GetFrontAngles()
  574. {
  575. if ( m_hDirectionalMarker != NULL )
  576. {
  577. return m_hDirectionalMarker->GetAbsAngles();
  578. }
  579. static QAngle invalid( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
  580. return invalid;
  581. }
  582. //-------------------------------------
  583. void CAI_FightFromCoverGoal::BeginMovingFront()
  584. {
  585. if ( m_hDirectionalMarker != NULL )
  586. {
  587. if ( m_hGoalEntity != NULL )
  588. {
  589. if ( !m_pfnThink )
  590. {
  591. SetThink( &CAI_FightFromCoverGoal::FrontThink );
  592. SetNextThink( gpGlobals->curtime + .1 );
  593. }
  594. }
  595. else
  596. {
  597. m_vFront = m_hDirectionalMarker->GetAbsOrigin();
  598. }
  599. }
  600. else
  601. {
  602. EndMovingFront();
  603. }
  604. }
  605. //-------------------------------------
  606. void CAI_FightFromCoverGoal::EndMovingFront()
  607. {
  608. SetThink( NULL );
  609. }
  610. //-------------------------------------
  611. void CAI_FightFromCoverGoal::OnActivate()
  612. {
  613. BeginMovingFront();
  614. }
  615. //-------------------------------------
  616. void CAI_FightFromCoverGoal::OnDeactivate()
  617. {
  618. EndMovingFront();
  619. }
  620. //-------------------------------------
  621. void CAI_FightFromCoverGoal::FrontThink()
  622. {
  623. if ( m_hDirectionalMarker != NULL && m_hGoalEntity != NULL )
  624. {
  625. Vector vClosest;
  626. AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir );
  627. CalcClosestPointOnLineSegment( m_hGoalEntity->GetAbsOrigin(), m_vFront, m_vFront + m_vDir * 99999, vClosest );
  628. m_vFront = vClosest;
  629. SetNextThink( gpGlobals->curtime + 0.5 );
  630. }
  631. else
  632. {
  633. EndMovingFront();
  634. }
  635. }
  636. //-------------------------------------
  637. void CAI_FightFromCoverGoal::EnableGoal( CAI_BaseNPC *pAI )
  638. {
  639. CAI_FightFromCoverBehavior *pBehavior;
  640. if ( !pAI->GetBehavior( &pBehavior ) )
  641. return;
  642. CBaseEntity *pGoalEntity = GetGoalEntity();
  643. if ( pGoalEntity )
  644. {
  645. pBehavior->SetGoal( this );
  646. }
  647. }
  648. //-------------------------------------
  649. void CAI_FightFromCoverGoal::DisableGoal( CAI_BaseNPC *pAI )
  650. {
  651. CAI_FightFromCoverBehavior *pBehavior;
  652. if ( !pAI || !pAI->GetBehavior( &pBehavior ) )
  653. return;
  654. pBehavior->ClearGoal();
  655. }
  656. //-------------------------------------
  657. void CAI_FightFromCoverGoal::ResolveNames()
  658. {
  659. BaseClass::ResolveNames();
  660. if ( m_hGoalEntity == NULL && AI_IsSinglePlayer() )
  661. {
  662. m_hGoalEntity = UTIL_GetLocalPlayer();
  663. }
  664. if ( m_DirectionalMarker != NULL_STRING )
  665. {
  666. EHANDLE hDirectionalMarker = gEntList.FindEntityByName( NULL, STRING(m_DirectionalMarker) );
  667. if ( m_hDirectionalMarker != hDirectionalMarker )
  668. {
  669. m_hDirectionalMarker = gEntList.FindEntityByName( NULL, STRING(m_DirectionalMarker) );
  670. m_vFront = m_hDirectionalMarker->GetAbsOrigin();
  671. AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir );
  672. }
  673. BeginMovingFront();
  674. }
  675. else
  676. {
  677. m_hDirectionalMarker = NULL;
  678. m_vDir.Invalidate();
  679. EndMovingFront();
  680. }
  681. }
  682. //-------------------------------------
  683. void CAI_FightFromCoverGoal::InputSetDirectionalMarker( inputdata_t &inputdata )
  684. {
  685. m_hDirectionalMarker = inputdata.value.Entity();
  686. if ( m_hDirectionalMarker != NULL )
  687. {
  688. m_DirectionalMarker = m_hDirectionalMarker->GetEntityName();
  689. m_vFront = m_hDirectionalMarker->GetAbsOrigin();
  690. AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir );
  691. BeginMovingFront();
  692. }
  693. else
  694. {
  695. m_DirectionalMarker = NULL_STRING;
  696. m_vDir.Invalidate();
  697. EndMovingFront();
  698. }
  699. }
  700. //-------------------------------------
  701. int CAI_FightFromCoverGoal::DrawDebugTextOverlays()
  702. {
  703. int text_offset = BaseClass::DrawDebugTextOverlays();
  704. if ( m_debugOverlays & OVERLAY_TEXT_BIT )
  705. {
  706. CFmtStr str;
  707. if ( m_hDirectionalMarker != NULL )
  708. {
  709. EntityText( text_offset++, str.sprintf( "Dir ent: %s", m_hDirectionalMarker->GetEntityNameAsCStr() ), 0 );
  710. NDebugOverlay::YawArrow( m_hDirectionalMarker->GetAbsOrigin() + Vector( 0, 0, 6 ), m_hDirectionalMarker->GetAbsAngles().y, 60, 6, 255, 255, 255, 0, true, 0 );
  711. NDebugOverlay::Cross3DOriented( m_vFront + Vector( 0, 0, 6 ), m_hDirectionalMarker->GetAbsAngles(), 12, 255, 0, 0, true, 0 );
  712. Vector vBoxDrawCenter;
  713. AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &vBoxDrawCenter );
  714. vBoxDrawCenter *= -m_BiasZone;
  715. vBoxDrawCenter += m_vFront;
  716. NDebugOverlay::BoxAngles( vBoxDrawCenter, Vector( -(m_LengthZone/2), -(m_WidthZone/2), -(m_HeightZone/2) ), Vector( m_LengthZone/2, m_WidthZone/2, m_HeightZone/2 ), m_hDirectionalMarker->GetAbsAngles(), 255, 0, 0, 16, 0 );
  717. for ( int i = 0; i < m_actors.Count(); i++ )
  718. {
  719. if ( m_actors[i] != NULL )
  720. {
  721. NDebugOverlay::Line( m_vFront, m_actors[i]->WorldSpaceCenter(), 0, 0, 127, true, 0 );
  722. }
  723. }
  724. }
  725. if ( m_hGoalEntity != NULL )
  726. {
  727. EntityText( text_offset++, str.sprintf( "Front ent: %s", m_hGoalEntity->GetEntityNameAsCStr() ), 0 );
  728. }
  729. }
  730. return text_offset;
  731. }