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.

938 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Bullseyes act as targets for other NPC's to attack and to trigger
  4. // events
  5. //
  6. // $Workfile: $
  7. // $Date: $
  8. //
  9. //-----------------------------------------------------------------------------
  10. // $Log: $
  11. //
  12. // $NoKeywords: $
  13. //=============================================================================//
  14. #include "cbase.h"
  15. #include "ai_default.h"
  16. #include "ai_task.h"
  17. #include "ai_schedule.h"
  18. #include "ai_node.h"
  19. #include "ai_hull.h"
  20. #include "ai_hint.h"
  21. #include "ai_memory.h"
  22. #include "ai_route.h"
  23. #include "ai_motor.h"
  24. #include "hl1_npc_barney.h"
  25. #include "soundent.h"
  26. #include "game.h"
  27. #include "npcevent.h"
  28. #include "entitylist.h"
  29. #include "activitylist.h"
  30. #include "animation.h"
  31. #include "basecombatweapon.h"
  32. #include "IEffects.h"
  33. #include "vstdlib/random.h"
  34. #include "engine/IEngineSound.h"
  35. #include "ammodef.h"
  36. #include "ai_behavior_follow.h"
  37. #include "AI_Criteria.h"
  38. #include "SoundEmitterSystem/isoundemittersystembase.h"
  39. #define BA_ATTACK "BA_ATTACK"
  40. #define BA_MAD "BA_MAD"
  41. #define BA_SHOT "BA_SHOT"
  42. #define BA_KILL "BA_KILL"
  43. #define BA_POK "BA_POK"
  44. ConVar sk_barney_health( "sk_barney_health","35");
  45. //=========================================================
  46. // Monster's Anim Events Go Here
  47. //=========================================================
  48. // first flag is barney dying for scripted sequences?
  49. #define BARNEY_AE_DRAW ( 2 )
  50. #define BARNEY_AE_SHOOT ( 3 )
  51. #define BARNEY_AE_HOLSTER ( 4 )
  52. #define BARNEY_BODY_GUNHOLSTERED 0
  53. #define BARNEY_BODY_GUNDRAWN 1
  54. #define BARNEY_BODY_GUNGONE 2
  55. //---------------------------------------------------------
  56. // Save/Restore
  57. //---------------------------------------------------------
  58. BEGIN_DATADESC( CNPC_Barney )
  59. DEFINE_FIELD( m_fGunDrawn, FIELD_BOOLEAN ),
  60. DEFINE_FIELD( m_flPainTime, FIELD_TIME ),
  61. DEFINE_FIELD( m_flCheckAttackTime, FIELD_TIME ),
  62. DEFINE_FIELD( m_fLastAttackCheck, FIELD_BOOLEAN ),
  63. DEFINE_THINKFUNC( SUB_LVFadeOut ),
  64. //DEFINE_FIELD( m_iAmmoType, FIELD_INTEGER ),
  65. END_DATADESC()
  66. LINK_ENTITY_TO_CLASS( monster_barney, CNPC_Barney );
  67. static BOOL IsFacing( CBaseEntity *pevTest, const Vector &reference )
  68. {
  69. Vector vecDir = (reference - pevTest->GetAbsOrigin());
  70. vecDir.z = 0;
  71. VectorNormalize( vecDir );
  72. Vector forward;
  73. QAngle angle;
  74. angle = pevTest->GetAbsAngles();
  75. angle.x = 0;
  76. AngleVectors( angle, &forward );
  77. // He's facing me, he meant it
  78. if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
  79. {
  80. return TRUE;
  81. }
  82. return FALSE;
  83. }
  84. //=========================================================
  85. // Spawn
  86. //=========================================================
  87. void CNPC_Barney::Spawn()
  88. {
  89. Precache( );
  90. SetModel( "models/barney.mdl");
  91. SetRenderColor( 255, 255, 255, 255 );
  92. SetHullType(HULL_HUMAN);
  93. SetHullSizeNormal();
  94. SetSolid( SOLID_BBOX );
  95. AddSolidFlags( FSOLID_NOT_STANDABLE );
  96. SetMoveType( MOVETYPE_STEP );
  97. m_bloodColor = BLOOD_COLOR_RED;
  98. m_iHealth = sk_barney_health.GetFloat();
  99. SetViewOffset( Vector ( 0, 0, 100 ) );// position of the eyes relative to monster's origin.
  100. m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
  101. m_NPCState = NPC_STATE_NONE;
  102. SetBodygroup( 1, 0 );
  103. m_fGunDrawn = false;
  104. CapabilitiesClear();
  105. CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE | bits_CAP_DOORS_GROUP);
  106. CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
  107. NPCInit();
  108. SetUse( &CNPC_Barney::FollowerUse );
  109. }
  110. //=========================================================
  111. // Precache - precaches all resources this monster needs
  112. //=========================================================
  113. void CNPC_Barney::Precache()
  114. {
  115. m_iAmmoType = GetAmmoDef()->Index("9mmRound");
  116. PrecacheModel("models/barney.mdl");
  117. PrecacheScriptSound( "Barney.FirePistol" );
  118. PrecacheScriptSound( "Barney.Pain" );
  119. PrecacheScriptSound( "Barney.Die" );
  120. // every new barney must call this, otherwise
  121. // when a level is loaded, nobody will talk (time is reset to 0)
  122. TalkInit();
  123. BaseClass::Precache();
  124. }
  125. void CNPC_Barney::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet )
  126. {
  127. BaseClass::ModifyOrAppendCriteria( criteriaSet );
  128. bool predisaster = FBitSet( m_spawnflags, SF_NPC_PREDISASTER ) ? true : false;
  129. criteriaSet.AppendCriteria( "disaster", predisaster ? "[disaster::pre]" : "[disaster::post]" );
  130. }
  131. // Init talk data
  132. void CNPC_Barney::TalkInit()
  133. {
  134. BaseClass::TalkInit();
  135. // get voice for head - just one barney voice for now
  136. GetExpresser()->SetVoicePitch( 100 );
  137. }
  138. //=========================================================
  139. // GetSoundInterests - returns a bit mask indicating which types
  140. // of sounds this monster regards.
  141. //=========================================================
  142. int CNPC_Barney::GetSoundInterests ( void)
  143. {
  144. return SOUND_WORLD |
  145. SOUND_COMBAT |
  146. SOUND_CARCASS |
  147. SOUND_MEAT |
  148. SOUND_GARBAGE |
  149. SOUND_DANGER |
  150. SOUND_PLAYER;
  151. }
  152. //=========================================================
  153. // Classify - indicates this monster's place in the
  154. // relationship table.
  155. //=========================================================
  156. Class_T CNPC_Barney::Classify ( void )
  157. {
  158. return CLASS_PLAYER_ALLY;
  159. }
  160. //=========================================================
  161. // ALertSound - barney says "Freeze!"
  162. //=========================================================
  163. void CNPC_Barney::AlertSound( void )
  164. {
  165. if ( GetEnemy() != NULL )
  166. {
  167. if ( IsOkToSpeak() )
  168. {
  169. Speak( BA_ATTACK );
  170. }
  171. }
  172. }
  173. //=========================================================
  174. // SetYawSpeed - allows each sequence to have a different
  175. // turn rate associated with it.
  176. //=========================================================
  177. void CNPC_Barney::SetYawSpeed ( void )
  178. {
  179. int ys;
  180. ys = 0;
  181. switch ( GetActivity() )
  182. {
  183. case ACT_IDLE:
  184. ys = 70;
  185. break;
  186. case ACT_WALK:
  187. ys = 70;
  188. break;
  189. case ACT_RUN:
  190. ys = 90;
  191. break;
  192. default:
  193. ys = 70;
  194. break;
  195. }
  196. GetMotor()->SetYawSpeed( ys );
  197. }
  198. //=========================================================
  199. // CheckRangeAttack1
  200. //=========================================================
  201. bool CNPC_Barney::CheckRangeAttack1 ( float flDot, float flDist )
  202. {
  203. if ( gpGlobals->curtime > m_flCheckAttackTime )
  204. {
  205. trace_t tr;
  206. Vector shootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 );
  207. CBaseEntity *pEnemy = GetEnemy();
  208. Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->GetAbsOrigin()) + GetEnemyLKP() );
  209. UTIL_TraceLine ( shootOrigin, shootTarget, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
  210. m_flCheckAttackTime = gpGlobals->curtime + 1;
  211. if ( tr.fraction == 1.0 || ( tr.m_pEnt != NULL && tr.m_pEnt == pEnemy) )
  212. m_fLastAttackCheck = TRUE;
  213. else
  214. m_fLastAttackCheck = FALSE;
  215. m_flCheckAttackTime = gpGlobals->curtime + 1.5;
  216. }
  217. return m_fLastAttackCheck;
  218. }
  219. //------------------------------------------------------------------------------
  220. // Purpose : For innate range attack
  221. // Input :
  222. // Output :
  223. //------------------------------------------------------------------------------
  224. int CNPC_Barney::RangeAttack1Conditions( float flDot, float flDist )
  225. {
  226. if (GetEnemy() == NULL)
  227. {
  228. return( COND_NONE );
  229. }
  230. else if ( flDist > 1024 )
  231. {
  232. return( COND_TOO_FAR_TO_ATTACK );
  233. }
  234. else if ( flDot < 0.5 )
  235. {
  236. return( COND_NOT_FACING_ATTACK );
  237. }
  238. if ( CheckRangeAttack1 ( flDot, flDist ) )
  239. return( COND_CAN_RANGE_ATTACK1 );
  240. return COND_NONE;
  241. }
  242. //=========================================================
  243. // BarneyFirePistol - shoots one round from the pistol at
  244. // the enemy barney is facing.
  245. //=========================================================
  246. void CNPC_Barney::BarneyFirePistol ( void )
  247. {
  248. Vector vecShootOrigin;
  249. vecShootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 );
  250. Vector vecShootDir = GetShootEnemyDir( vecShootOrigin );
  251. QAngle angDir;
  252. VectorAngles( vecShootDir, angDir );
  253. // SetBlending( 0, angDir.x );
  254. DoMuzzleFlash();
  255. FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, m_iAmmoType );
  256. int pitchShift = random->RandomInt( 0, 20 );
  257. // Only shift about half the time
  258. if ( pitchShift > 10 )
  259. pitchShift = 0;
  260. else
  261. pitchShift -= 5;
  262. CPASAttenuationFilter filter( this );
  263. EmitSound_t params;
  264. params.m_pSoundName = "Barney.FirePistol";
  265. params.m_flVolume = 1;
  266. params.m_nChannel= CHAN_WEAPON;
  267. params.m_SoundLevel = SNDLVL_NORM;
  268. params.m_nPitch = 100 + pitchShift;
  269. EmitSound( filter, entindex(), params );
  270. CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), 384, 0.3 );
  271. // UNDONE: Reload?
  272. m_cAmmoLoaded--;// take away a bullet!
  273. }
  274. int CNPC_Barney::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
  275. {
  276. // make sure friends talk about it if player hurts talkmonsters...
  277. int ret = BaseClass::OnTakeDamage_Alive( inputInfo );
  278. if ( !IsAlive() || m_lifeState == LIFE_DYING )
  279. return ret;
  280. if ( m_NPCState != NPC_STATE_PRONE && ( inputInfo.GetAttacker()->GetFlags() & FL_CLIENT ) )
  281. {
  282. // This is a heurstic to determine if the player intended to harm me
  283. // If I have an enemy, we can't establish intent (may just be crossfire)
  284. if ( GetEnemy() == NULL )
  285. {
  286. // If the player was facing directly at me, or I'm already suspicious, get mad
  287. if ( HasMemory( bits_MEMORY_SUSPICIOUS ) || IsFacing( inputInfo.GetAttacker(), GetAbsOrigin() ) )
  288. {
  289. // Alright, now I'm pissed!
  290. Speak( BA_MAD );
  291. Remember( bits_MEMORY_PROVOKED );
  292. StopFollowing();
  293. }
  294. else
  295. {
  296. // Hey, be careful with that
  297. Speak( BA_SHOT );
  298. Remember( bits_MEMORY_SUSPICIOUS );
  299. }
  300. }
  301. else if ( !(GetEnemy()->IsPlayer()) && m_lifeState == LIFE_ALIVE )
  302. {
  303. Speak( BA_SHOT );
  304. }
  305. }
  306. return ret;
  307. }
  308. //=========================================================
  309. // PainSound
  310. //=========================================================
  311. void CNPC_Barney::PainSound( const CTakeDamageInfo &info )
  312. {
  313. if (gpGlobals->curtime < m_flPainTime)
  314. return;
  315. m_flPainTime = gpGlobals->curtime + random->RandomFloat( 0.5, 0.75 );
  316. CPASAttenuationFilter filter( this );
  317. CSoundParameters params;
  318. if ( GetParametersForSound( "Barney.Pain", params, NULL ) )
  319. {
  320. params.pitch = GetExpresser()->GetVoicePitch();
  321. EmitSound_t ep( params );
  322. EmitSound( filter, entindex(), ep );
  323. }
  324. }
  325. //=========================================================
  326. // DeathSound
  327. //=========================================================
  328. void CNPC_Barney::DeathSound( const CTakeDamageInfo &info )
  329. {
  330. CPASAttenuationFilter filter( this );
  331. CSoundParameters params;
  332. if ( GetParametersForSound( "Barney.Die", params, NULL ) )
  333. {
  334. params.pitch = GetExpresser()->GetVoicePitch();
  335. EmitSound_t ep( params );
  336. EmitSound( filter, entindex(), ep );
  337. }
  338. }
  339. void CNPC_Barney::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
  340. {
  341. CTakeDamageInfo info = inputInfo;
  342. switch( ptr->hitgroup )
  343. {
  344. case HITGROUP_CHEST:
  345. case HITGROUP_STOMACH:
  346. if ( info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_BLAST) )
  347. {
  348. info.ScaleDamage( 0.5f );
  349. }
  350. break;
  351. case 10:
  352. if ( info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB) )
  353. {
  354. info.SetDamage( info.GetDamage() - 20 );
  355. if ( info.GetDamage() <= 0 )
  356. {
  357. g_pEffects->Ricochet( ptr->endpos, ptr->plane.normal );
  358. info.SetDamage( 0.01 );
  359. }
  360. }
  361. // always a head shot
  362. ptr->hitgroup = HITGROUP_HEAD;
  363. break;
  364. }
  365. BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
  366. }
  367. void CNPC_Barney::Event_Killed( const CTakeDamageInfo &info )
  368. {
  369. if ( m_nBody < BARNEY_BODY_GUNGONE )
  370. {
  371. // drop the gun!
  372. Vector vecGunPos;
  373. QAngle angGunAngles;
  374. CBaseEntity *pGun = NULL;
  375. SetBodygroup( 1, BARNEY_BODY_GUNGONE);
  376. GetAttachment( "0", vecGunPos, angGunAngles );
  377. angGunAngles.y += 180;
  378. pGun = DropItem( "weapon_glock", vecGunPos, angGunAngles );
  379. }
  380. SetUse( NULL );
  381. BaseClass::Event_Killed( info );
  382. if ( UTIL_IsLowViolence() )
  383. {
  384. SUB_StartLVFadeOut( 0.0f );
  385. }
  386. }
  387. void CNPC_Barney::SUB_StartLVFadeOut( float delay, bool notSolid )
  388. {
  389. SetThink( &CNPC_Barney::SUB_LVFadeOut );
  390. SetNextThink( gpGlobals->curtime + delay );
  391. SetRenderColorA( 255 );
  392. m_nRenderMode = kRenderNormal;
  393. if ( notSolid )
  394. {
  395. AddSolidFlags( FSOLID_NOT_SOLID );
  396. SetLocalAngularVelocity( vec3_angle );
  397. }
  398. }
  399. void CNPC_Barney::SUB_LVFadeOut( void )
  400. {
  401. if( VPhysicsGetObject() )
  402. {
  403. if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE )
  404. {
  405. // Try again in a few seconds.
  406. SetNextThink( gpGlobals->curtime + 5 );
  407. SetRenderColorA( 255 );
  408. return;
  409. }
  410. }
  411. float dt = gpGlobals->frametime;
  412. if ( dt > 0.1f )
  413. {
  414. dt = 0.1f;
  415. }
  416. m_nRenderMode = kRenderTransTexture;
  417. int speed = MAX(3,256*dt); // fade out over 3 seconds
  418. SetRenderColorA( UTIL_Approach( 0, m_clrRender->a, speed ) );
  419. NetworkStateChanged();
  420. if ( m_clrRender->a == 0 )
  421. {
  422. UTIL_Remove(this);
  423. }
  424. else
  425. {
  426. SetNextThink( gpGlobals->curtime );
  427. }
  428. }
  429. void CNPC_Barney::StartTask( const Task_t *pTask )
  430. {
  431. BaseClass::StartTask( pTask );
  432. }
  433. void CNPC_Barney::RunTask( const Task_t *pTask )
  434. {
  435. switch ( pTask->iTask )
  436. {
  437. case TASK_RANGE_ATTACK1:
  438. if (GetEnemy() != NULL && (GetEnemy()->IsPlayer()))
  439. {
  440. m_flPlaybackRate = 1.5;
  441. }
  442. BaseClass::RunTask( pTask );
  443. break;
  444. default:
  445. BaseClass::RunTask( pTask );
  446. break;
  447. }
  448. }
  449. //=========================================================
  450. // HandleAnimEvent - catches the monster-specific messages
  451. // that occur when tagged animation frames are played.
  452. //
  453. // Returns number of events handled, 0 if none.
  454. //=========================================================
  455. void CNPC_Barney::HandleAnimEvent( animevent_t *pEvent )
  456. {
  457. switch( pEvent->event )
  458. {
  459. case BARNEY_AE_SHOOT:
  460. BarneyFirePistol();
  461. break;
  462. case BARNEY_AE_DRAW:
  463. // barney's bodygroup switches here so he can pull gun from holster
  464. SetBodygroup( 1, BARNEY_BODY_GUNDRAWN);
  465. m_fGunDrawn = true;
  466. break;
  467. case BARNEY_AE_HOLSTER:
  468. // change bodygroup to replace gun in holster
  469. SetBodygroup( 1, BARNEY_BODY_GUNHOLSTERED);
  470. m_fGunDrawn = false;
  471. break;
  472. default:
  473. BaseClass::HandleAnimEvent( pEvent );
  474. }
  475. }
  476. //=========================================================
  477. // AI Schedules Specific to this monster
  478. //=========================================================
  479. int CNPC_Barney::TranslateSchedule( int scheduleType )
  480. {
  481. switch( scheduleType )
  482. {
  483. case SCHED_ARM_WEAPON:
  484. if ( GetEnemy() != NULL )
  485. {
  486. // face enemy, then draw.
  487. return SCHED_BARNEY_ENEMY_DRAW;
  488. }
  489. break;
  490. // Hook these to make a looping schedule
  491. case SCHED_TARGET_FACE:
  492. {
  493. int baseType;
  494. // call base class default so that scientist will talk
  495. // when 'used'
  496. baseType = BaseClass::TranslateSchedule( scheduleType );
  497. if ( baseType == SCHED_IDLE_STAND )
  498. return SCHED_BARNEY_FACE_TARGET;
  499. else
  500. return baseType;
  501. }
  502. break;
  503. case SCHED_TARGET_CHASE:
  504. {
  505. return SCHED_BARNEY_FOLLOW;
  506. break;
  507. }
  508. case SCHED_IDLE_STAND:
  509. {
  510. int baseType;
  511. // call base class default so that scientist will talk
  512. // when 'used'
  513. baseType = BaseClass::TranslateSchedule( scheduleType );
  514. if ( baseType == SCHED_IDLE_STAND )
  515. return SCHED_BARNEY_IDLE_STAND;
  516. else
  517. return baseType;
  518. }
  519. break;
  520. case SCHED_TAKE_COVER_FROM_ENEMY:
  521. case SCHED_CHASE_ENEMY:
  522. {
  523. if ( HasCondition( COND_HEAVY_DAMAGE ) )
  524. return SCHED_TAKE_COVER_FROM_ENEMY;
  525. // No need to take cover since I can see him
  526. // SHOOT!
  527. if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && m_fGunDrawn )
  528. return SCHED_RANGE_ATTACK1;
  529. }
  530. break;
  531. }
  532. return BaseClass::TranslateSchedule( scheduleType );
  533. }
  534. //=========================================================
  535. // SelectSchedule - Decides which type of schedule best suits
  536. // the monster's current state and conditions. Then calls
  537. // monster's member function to get a pointer to a schedule
  538. // of the proper type.
  539. //=========================================================
  540. int CNPC_Barney::SelectSchedule( void )
  541. {
  542. if ( m_NPCState == NPC_STATE_COMBAT || GetEnemy() != NULL )
  543. {
  544. // Priority action!
  545. if (!m_fGunDrawn )
  546. return SCHED_ARM_WEAPON;
  547. }
  548. if ( GetFollowTarget() == NULL )
  549. {
  550. if ( HasCondition( COND_PLAYER_PUSHING ) && !(GetSpawnFlags() & SF_NPC_PREDISASTER ) ) // Player wants me to move
  551. return SCHED_HL1TALKER_FOLLOW_MOVE_AWAY;
  552. }
  553. if ( BehaviorSelectSchedule() )
  554. return BaseClass::SelectSchedule();
  555. if ( HasCondition( COND_HEAR_DANGER ) )
  556. {
  557. CSound *pSound;
  558. pSound = GetBestSound();
  559. ASSERT( pSound != NULL );
  560. if ( pSound && pSound->IsSoundType( SOUND_DANGER ) )
  561. return SCHED_TAKE_COVER_FROM_BEST_SOUND;
  562. }
  563. if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToSpeak() )
  564. {
  565. Speak( BA_KILL );
  566. }
  567. switch( m_NPCState )
  568. {
  569. case NPC_STATE_COMBAT:
  570. {
  571. // dead enemy
  572. if ( HasCondition( COND_ENEMY_DEAD ) )
  573. return BaseClass::SelectSchedule(); // call base class, all code to handle dead enemies is centralized there.
  574. // always act surprized with a new enemy
  575. if ( HasCondition( COND_NEW_ENEMY ) && HasCondition( COND_LIGHT_DAMAGE) )
  576. return SCHED_SMALL_FLINCH;
  577. if ( HasCondition( COND_HEAVY_DAMAGE ) )
  578. return SCHED_TAKE_COVER_FROM_ENEMY;
  579. if ( !HasCondition(COND_SEE_ENEMY) )
  580. {
  581. // we can't see the enemy
  582. if ( !HasCondition(COND_ENEMY_OCCLUDED) )
  583. {
  584. // enemy is unseen, but not occluded!
  585. // turn to face enemy
  586. return SCHED_COMBAT_FACE;
  587. }
  588. else
  589. {
  590. return SCHED_CHASE_ENEMY;
  591. }
  592. }
  593. }
  594. break;
  595. case NPC_STATE_ALERT:
  596. case NPC_STATE_IDLE:
  597. if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
  598. {
  599. // flinch if hurt
  600. return SCHED_SMALL_FLINCH;
  601. }
  602. if ( GetEnemy() == NULL && GetFollowTarget() )
  603. {
  604. if ( !GetFollowTarget()->IsAlive() )
  605. {
  606. // UNDONE: Comment about the recently dead player here?
  607. StopFollowing();
  608. break;
  609. }
  610. else
  611. {
  612. return SCHED_TARGET_FACE;
  613. }
  614. }
  615. // try to say something about smells
  616. TrySmellTalk();
  617. break;
  618. }
  619. return BaseClass::SelectSchedule();
  620. }
  621. NPC_STATE CNPC_Barney::SelectIdealState ( void )
  622. {
  623. return BaseClass::SelectIdealState();
  624. }
  625. void CNPC_Barney::DeclineFollowing( void )
  626. {
  627. if ( CanSpeakAfterMyself() )
  628. {
  629. Speak( BA_POK );
  630. }
  631. }
  632. bool CNPC_Barney::CanBecomeRagdoll( void )
  633. {
  634. if ( UTIL_IsLowViolence() )
  635. {
  636. return false;
  637. }
  638. return BaseClass::CanBecomeRagdoll();
  639. }
  640. bool CNPC_Barney::ShouldGib( const CTakeDamageInfo &info )
  641. {
  642. if ( UTIL_IsLowViolence() )
  643. {
  644. return false;
  645. }
  646. return BaseClass::ShouldGib( info );
  647. }
  648. //------------------------------------------------------------------------------
  649. //
  650. // Schedules
  651. //
  652. //------------------------------------------------------------------------------
  653. AI_BEGIN_CUSTOM_NPC( monster_barney, CNPC_Barney )
  654. //=========================================================
  655. // > SCHED_BARNEY_FOLLOW
  656. //=========================================================
  657. DEFINE_SCHEDULE
  658. (
  659. SCHED_BARNEY_FOLLOW,
  660. " Tasks"
  661. // " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_BARNEY_STOP_FOLLOWING"
  662. " TASK_GET_PATH_TO_TARGET 0"
  663. " TASK_MOVE_TO_TARGET_RANGE 180"
  664. " TASK_SET_SCHEDULE SCHEDULE:SCHED_TARGET_FACE"
  665. " "
  666. " Interrupts"
  667. " COND_NEW_ENEMY"
  668. " COND_LIGHT_DAMAGE"
  669. " COND_HEAVY_DAMAGE"
  670. " COND_HEAR_DANGER"
  671. " COND_PROVOKED"
  672. )
  673. //=========================================================
  674. // > SCHED_BARNEY_ENEMY_DRAW
  675. //=========================================================
  676. DEFINE_SCHEDULE
  677. (
  678. SCHED_BARNEY_ENEMY_DRAW,
  679. " Tasks"
  680. " TASK_STOP_MOVING 0"
  681. " TASK_FACE_ENEMY 0"
  682. " TASK_PLAY_SEQUENCE_FACE_ENEMY ACTIVITY:ACT_ARM"
  683. " "
  684. " Interrupts"
  685. )
  686. //=========================================================
  687. // > SCHED_BARNEY_FACE_TARGET
  688. //=========================================================
  689. DEFINE_SCHEDULE
  690. (
  691. SCHED_BARNEY_FACE_TARGET,
  692. " Tasks"
  693. " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
  694. " TASK_FACE_TARGET 0"
  695. " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
  696. " TASK_SET_SCHEDULE SCHEDULE:SCHED_BARNEY_FOLLOW"
  697. " "
  698. " Interrupts"
  699. " COND_GIVE_WAY"
  700. " COND_NEW_ENEMY"
  701. " COND_LIGHT_DAMAGE"
  702. " COND_HEAVY_DAMAGE"
  703. " COND_PROVOKED"
  704. " COND_HEAR_DANGER"
  705. )
  706. //=========================================================
  707. // > SCHED_BARNEY_IDLE_STAND
  708. //=========================================================
  709. DEFINE_SCHEDULE
  710. (
  711. SCHED_BARNEY_IDLE_STAND,
  712. " Tasks"
  713. " TASK_STOP_MOVING 0"
  714. " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
  715. " TASK_WAIT 2"
  716. " TASK_TALKER_HEADRESET 0"
  717. " "
  718. " Interrupts"
  719. " COND_NEW_ENEMY"
  720. " COND_LIGHT_DAMAGE"
  721. " COND_HEAVY_DAMAGE"
  722. " COND_PROVOKED"
  723. " COND_HEAR_COMBAT"
  724. " COND_SMELL"
  725. )
  726. AI_END_CUSTOM_NPC()
  727. //=========================================================
  728. // DEAD BARNEY PROP
  729. //
  730. // Designer selects a pose in worldcraft, 0 through num_poses-1
  731. // this value is added to what is selected as the 'first dead pose'
  732. // among the monster's normal animations. All dead poses must
  733. // appear sequentially in the model file. Be sure and set
  734. // the m_iFirstPose properly!
  735. //
  736. //=========================================================
  737. class CNPC_DeadBarney : public CAI_BaseNPC
  738. {
  739. DECLARE_CLASS( CNPC_DeadBarney, CAI_BaseNPC );
  740. public:
  741. void Spawn( void );
  742. Class_T Classify ( void ) { return CLASS_NONE; }
  743. bool KeyValue( const char *szKeyName, const char *szValue );
  744. float MaxYawSpeed ( void ) { return 8.0f; }
  745. int m_iPose;// which sequence to display -- temporary, don't need to save
  746. int m_iDesiredSequence;
  747. static char *m_szPoses[3];
  748. DECLARE_DATADESC();
  749. };
  750. char *CNPC_DeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
  751. bool CNPC_DeadBarney::KeyValue( const char *szKeyName, const char *szValue )
  752. {
  753. if ( FStrEq( szKeyName, "pose" ) )
  754. m_iPose = atoi( szValue );
  755. else
  756. BaseClass::KeyValue( szKeyName, szValue );
  757. return true;
  758. }
  759. LINK_ENTITY_TO_CLASS( monster_barney_dead, CNPC_DeadBarney );
  760. BEGIN_DATADESC( CNPC_DeadBarney )
  761. END_DATADESC()
  762. //=========================================================
  763. // ********** DeadBarney SPAWN **********
  764. //=========================================================
  765. void CNPC_DeadBarney::Spawn( void )
  766. {
  767. PrecacheModel("models/barney.mdl");
  768. SetModel( "models/barney.mdl");
  769. ClearEffects();
  770. SetSequence( 0 );
  771. m_bloodColor = BLOOD_COLOR_RED;
  772. SetRenderColor( 255, 255, 255, 255 );
  773. SetSequence( m_iDesiredSequence = LookupSequence( m_szPoses[m_iPose] ) );
  774. if ( GetSequence() == -1 )
  775. {
  776. Msg ( "Dead barney with bad pose\n" );
  777. }
  778. // Corpses have less health
  779. m_iHealth = 0.0;//gSkillData.barneyHealth;
  780. NPCInitDead();
  781. }