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.

612 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //=========================================================
  9. // Generic NPC - purely for scripted sequence work.
  10. //=========================================================
  11. #include "cbase.h"
  12. #include "npcevent.h"
  13. #include "ai_basenpc.h"
  14. #include "ai_hull.h"
  15. #include "keyvalues.h"
  16. #include "engine/IEngineSound.h"
  17. #include "physics_bone_follower.h"
  18. #include "ai_baseactor.h"
  19. #include "ai_senses.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. // For holograms, make them not solid so the player can walk through them
  23. #define SF_GENERICNPC_NOTSOLID (1 << 16)
  24. //=========================================================
  25. // NPC's Anim Events Go Here
  26. //=========================================================
  27. class CGenericNPC : public CAI_BaseNPC
  28. {
  29. public:
  30. DECLARE_CLASS( CGenericNPC, CAI_BaseNPC );
  31. void Spawn( void );
  32. void Precache( void );
  33. float MaxYawSpeed( void );
  34. Class_T Classify ( void );
  35. void HandleAnimEvent( animevent_t *pEvent );
  36. int GetSoundInterests ( void );
  37. void TempGunEffect( void );
  38. };
  39. LINK_ENTITY_TO_CLASS( monster_generic, CGenericNPC );
  40. //=========================================================
  41. // Classify - indicates this NPC's place in the
  42. // relationship table.
  43. //=========================================================
  44. Class_T CGenericNPC::Classify ( void )
  45. {
  46. return CLASS_NONE;
  47. }
  48. //=========================================================
  49. // MaxYawSpeed - allows each sequence to have a different
  50. // turn rate associated with it.
  51. //=========================================================
  52. float CGenericNPC::MaxYawSpeed ( void )
  53. {
  54. return 90;
  55. }
  56. //---------------------------------------------------------
  57. // !!!TEMP
  58. // !!!TEMP
  59. // !!!TEMP
  60. // !!!TEMP
  61. //
  62. // (sjb)
  63. //---------------------------------------------------------
  64. void CGenericNPC::TempGunEffect( void )
  65. {
  66. QAngle vecAngle;
  67. Vector vecDir, vecShot;
  68. Vector vecMuzzle, vecButt;
  69. GetAttachment( 2, vecMuzzle, vecAngle );
  70. GetAttachment( 3, vecButt, vecAngle );
  71. vecDir = vecMuzzle - vecButt;
  72. VectorNormalize( vecDir );
  73. // CPVSFilter filter( GetAbsOrigin() );
  74. //te->ShowLine( filter, 0.0, vecSpot, vecSpot + vecForward );
  75. //UTIL_Sparks( vecMuzzle );
  76. bool fSound = false;
  77. if( random->RandomInt( 0, 3 ) == 0 )
  78. {
  79. fSound = true;
  80. }
  81. Vector start = vecMuzzle + vecDir * 64;
  82. Vector end = vecMuzzle + vecDir * 4096;
  83. UTIL_Tracer( start, end, 0, TRACER_DONT_USE_ATTACHMENT, 5500, fSound );
  84. CPASAttenuationFilter filter2( this, "GenericNPC.GunSound" );
  85. EmitSound( filter2, entindex(), "GenericNPC.GunSound" );
  86. }
  87. //=========================================================
  88. // HandleAnimEvent - catches the NPC-specific messages
  89. // that occur when tagged animation frames are played.
  90. //=========================================================
  91. void CGenericNPC::HandleAnimEvent( animevent_t *pEvent )
  92. {
  93. switch( pEvent->Event() )
  94. {
  95. case 1:
  96. // TEMPORARLY. Makes the May 2001 sniper demo work (sjb)
  97. TempGunEffect();
  98. break;
  99. default:
  100. BaseClass::HandleAnimEvent( pEvent );
  101. break;
  102. }
  103. }
  104. //=========================================================
  105. // GetSoundInterests - generic NPC can't hear.
  106. //=========================================================
  107. int CGenericNPC::GetSoundInterests ( void )
  108. {
  109. return NULL;
  110. }
  111. //=========================================================
  112. // Spawn
  113. //=========================================================
  114. void CGenericNPC::Spawn()
  115. {
  116. Precache();
  117. SetModel( STRING( GetModelName() ) );
  118. /*
  119. if ( FStrEq( STRING( GetModelName() ), "models/player.mdl" ) )
  120. UTIL_SetSize(this, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
  121. else
  122. UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
  123. */
  124. if ( FStrEq( STRING( GetModelName() ), "models/player.mdl" ) || FStrEq( STRING( GetModelName() ), "models/holo.mdl" ) )
  125. UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
  126. else
  127. UTIL_SetSize(this, NAI_Hull::Mins(HULL_HUMAN), NAI_Hull::Maxs(HULL_HUMAN));
  128. SetSolid( SOLID_BBOX );
  129. AddSolidFlags( FSOLID_NOT_STANDABLE );
  130. SetMoveType( MOVETYPE_STEP );
  131. m_bloodColor = BLOOD_COLOR_RED;
  132. m_iHealth = 8;
  133. m_flFieldOfView = 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result )
  134. m_NPCState = NPC_STATE_NONE;
  135. CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS );
  136. NPCInit();
  137. if ( !HasSpawnFlags(SF_GENERICNPC_NOTSOLID) )
  138. {
  139. trace_t tr;
  140. UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), MASK_SOLID, &tr );
  141. if ( tr.startsolid )
  142. {
  143. Msg("Placed npc_generic in solid!!! (%s)\n", STRING(GetModelName()) );
  144. m_spawnflags |= SF_GENERICNPC_NOTSOLID;
  145. }
  146. }
  147. if ( HasSpawnFlags(SF_GENERICNPC_NOTSOLID) )
  148. {
  149. AddSolidFlags( FSOLID_NOT_SOLID );
  150. m_takedamage = DAMAGE_NO;
  151. VPhysicsDestroyObject();
  152. }
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: precaches all resources this NPC needs
  156. //-----------------------------------------------------------------------------
  157. void CGenericNPC::Precache()
  158. {
  159. BaseClass::Precache();
  160. PrecacheModel( STRING( GetModelName() ) );
  161. PrecacheScriptSound( "GenericNPC.GunSound" );
  162. }
  163. // a really large health is set to make sure these never die.
  164. const int TOO_MUCH_HEALTH_TO_DIE = 1000;
  165. //=======================================================================================
  166. // Furniture: A dumb "NPC" that is uses in scripted sequences
  167. // where an NPC needs to be frame locked with a prop.
  168. //=======================================================================================
  169. class CNPC_Furniture : public CAI_BaseActor
  170. {
  171. DECLARE_CLASS( CNPC_Furniture, CAI_BaseActor );
  172. DECLARE_DATADESC();
  173. public:
  174. void Spawn( void );
  175. void Precache( void );
  176. void Die( void );
  177. void UpdateEfficiency( bool bInPVS ) { SetEfficiency( ( GetSleepState() != AISS_AWAKE ) ? AIE_DORMANT : AIE_NORMAL ); SetMoveEfficiency( AIME_NORMAL ); }
  178. Class_T Classify ( void );
  179. float MaxYawSpeed( void ){ return 0; }
  180. virtual int ObjectCaps( void );
  181. bool CreateVPhysics( void );
  182. void NPCThink( void );
  183. void UpdateOnRemove( void );
  184. int SelectSchedule( void );
  185. void OnRestore( void );
  186. int OnTakeDamage( const CTakeDamageInfo &info )
  187. {
  188. if ( m_iHealth <= info.GetDamage() )
  189. m_iHealth = info.GetDamage() + TOO_MUCH_HEALTH_TO_DIE;
  190. return BaseClass::OnTakeDamage(info);
  191. }
  192. void DrawDebugGeometryOverlays(void);
  193. void SetPlayerAvoidState( void );
  194. void InputDisablePlayerCollision( inputdata_t &inputdata );
  195. void InputEnablePlayerCollision( inputdata_t &inputdata );
  196. void UpdateBoneFollowerState( void );
  197. int GetSoundInterests ( void );
  198. private:
  199. // Contained Bone Follower manager
  200. CBoneFollowerManager m_BoneFollowerManager;
  201. };
  202. LINK_ENTITY_TO_CLASS( monster_furniture, CNPC_Furniture );
  203. LINK_ENTITY_TO_CLASS( npc_furniture, CNPC_Furniture );
  204. //-----------------------------------------------------------------------------
  205. // Save/load
  206. //-----------------------------------------------------------------------------
  207. BEGIN_DATADESC( CNPC_Furniture )
  208. DEFINE_EMBEDDED( m_BoneFollowerManager ),
  209. DEFINE_INPUTFUNC( FIELD_VOID, "DisablePlayerCollision", InputDisablePlayerCollision ),
  210. DEFINE_INPUTFUNC( FIELD_VOID, "EnablePlayerCollision", InputEnablePlayerCollision ),
  211. END_DATADESC()
  212. //-----------------------------------------------------------------------------
  213. // Purpose: This used to have something to do with bees flying, but
  214. // now it only initializes moving furniture in scripted sequences
  215. //-----------------------------------------------------------------------------
  216. void CNPC_Furniture::Spawn( )
  217. {
  218. Precache();
  219. SetModel( STRING(GetModelName()) );
  220. SetMoveType( MOVETYPE_STEP );
  221. SetSolid( SOLID_BBOX );
  222. // Our collision, if needed, will be done through bone followers
  223. AddSolidFlags( FSOLID_NOT_SOLID );
  224. SetBloodColor( DONT_BLEED );
  225. m_iHealth = TOO_MUCH_HEALTH_TO_DIE; //wow
  226. m_takedamage = DAMAGE_AIM;
  227. SetSequence( 0 );
  228. SetCycle( 0 );
  229. SetNavType( NAV_FLY );
  230. AddFlag( FL_FLY );
  231. CapabilitiesAdd( bits_CAP_MOVE_FLY | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
  232. AddEFlags( EFL_NO_MEGAPHYSCANNON_RAGDOLL );
  233. // pev->nextthink += 1.0;
  234. // SetThink (WalkMonsterDelay);
  235. ResetSequenceInfo( );
  236. SetCycle( 0 );
  237. NPCInit();
  238. // Furniture needs to block LOS
  239. SetBlocksLOS( true );
  240. // Furniture just wastes CPU doing sensing code, since all they do is idle and play scripts
  241. GetSenses()->AddSensingFlags( SENSING_FLAGS_DONT_LOOK | SENSING_FLAGS_DONT_LISTEN );
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose:
  245. //-----------------------------------------------------------------------------
  246. void CNPC_Furniture::Precache( void )
  247. {
  248. PrecacheModel( STRING( GetModelName() ) );
  249. }
  250. //=========================================================
  251. // GetSoundInterests - generic NPC can't hear.
  252. //=========================================================
  253. int CNPC_Furniture::GetSoundInterests( void )
  254. {
  255. return NULL;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. //-----------------------------------------------------------------------------
  260. int CNPC_Furniture::ObjectCaps( void )
  261. {
  262. // HL2 furniture transitions
  263. #ifdef HL2_DLL
  264. return CAI_BaseNPC::ObjectCaps();
  265. #else
  266. return (CAI_BaseNPC::ObjectCaps() & ~FCAP_ACROSS_TRANSITION);
  267. #endif
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Furniture is killed
  271. //-----------------------------------------------------------------------------
  272. void CNPC_Furniture::Die( void )
  273. {
  274. SetThink ( &CNPC_Furniture::SUB_Remove );
  275. SetNextThink( gpGlobals->curtime );
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: ID's Furniture as neutral (noone will attack it)
  279. //-----------------------------------------------------------------------------
  280. Class_T CNPC_Furniture::Classify ( void )
  281. {
  282. return CLASS_NONE;
  283. }
  284. //------------------------------------------------------------------------------
  285. // Purpose:
  286. //------------------------------------------------------------------------------
  287. bool CNPC_Furniture::CreateVPhysics( void )
  288. {
  289. #ifndef HL2_DLL
  290. return false;
  291. #endif
  292. if ( !m_BoneFollowerManager.GetNumBoneFollowers() )
  293. {
  294. KeyValues *modelKeyValues = new KeyValues("");
  295. if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) )
  296. {
  297. // Do we have a bone follower section?
  298. KeyValues *pkvBoneFollowers = modelKeyValues->FindKey("bone_followers");
  299. if ( pkvBoneFollowers )
  300. {
  301. // Loop through the list and create the bone followers
  302. KeyValues *pBone = pkvBoneFollowers->GetFirstSubKey();
  303. while ( pBone )
  304. {
  305. // Add it to the list
  306. const char *pBoneName = pBone->GetString();
  307. m_BoneFollowerManager.AddBoneFollower( this, pBoneName );
  308. pBone = pBone->GetNextKey();
  309. }
  310. }
  311. }
  312. modelKeyValues->deleteThis();
  313. }
  314. return true;
  315. }
  316. void CNPC_Furniture::InputDisablePlayerCollision( inputdata_t &inputdata )
  317. {
  318. SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR );
  319. UpdateBoneFollowerState();
  320. }
  321. void CNPC_Furniture::InputEnablePlayerCollision( inputdata_t &inputdata )
  322. {
  323. SetCollisionGroup( COLLISION_GROUP_NPC );
  324. UpdateBoneFollowerState();
  325. }
  326. void CNPC_Furniture::UpdateBoneFollowerState( void )
  327. {
  328. if ( m_BoneFollowerManager.GetNumBoneFollowers() )
  329. {
  330. physfollower_t* pBone = m_BoneFollowerManager.GetBoneFollower( 0 );
  331. if ( pBone && pBone->hFollower && pBone->hFollower->GetCollisionGroup() != GetCollisionGroup() )
  332. {
  333. for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
  334. {
  335. pBone = m_BoneFollowerManager.GetBoneFollower( i );
  336. if ( pBone && pBone->hFollower )
  337. {
  338. pBone->hFollower->SetCollisionGroup( GetCollisionGroup() );
  339. }
  340. }
  341. }
  342. }
  343. }
  344. void CNPC_Furniture::SetPlayerAvoidState( void )
  345. {
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. //-----------------------------------------------------------------------------
  350. void CNPC_Furniture::NPCThink( void )
  351. {
  352. BaseClass::NPCThink();
  353. // Update follower bones
  354. m_BoneFollowerManager.UpdateBoneFollowers(this);
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose:
  358. //-----------------------------------------------------------------------------
  359. void CNPC_Furniture::UpdateOnRemove( void )
  360. {
  361. m_BoneFollowerManager.DestroyBoneFollowers();
  362. BaseClass::UpdateOnRemove();
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. // Output : int
  367. //-----------------------------------------------------------------------------
  368. int CNPC_Furniture::SelectSchedule( void )
  369. {
  370. switch( m_NPCState )
  371. {
  372. case NPC_STATE_NONE:
  373. case NPC_STATE_PRONE:
  374. case NPC_STATE_IDLE:
  375. case NPC_STATE_ALERT:
  376. case NPC_STATE_COMBAT:
  377. case NPC_STATE_DEAD:
  378. return SCHED_WAIT_FOR_SCRIPT;
  379. case NPC_STATE_SCRIPT:
  380. return BaseClass::SelectSchedule();
  381. default:
  382. DevWarning( 2, "Invalid State for SelectSchedule!\n" );
  383. break;
  384. }
  385. return SCHED_FAIL;
  386. }
  387. //-----------------------------------------------------------------------------
  388. // Purpose:
  389. //-----------------------------------------------------------------------------
  390. void CNPC_Furniture::OnRestore( void )
  391. {
  392. // Recreate any bone followers we have
  393. CreateVPhysics();
  394. BaseClass::OnRestore();
  395. }
  396. void CNPC_Furniture::DrawDebugGeometryOverlays( void )
  397. {
  398. //ugh
  399. if ( m_debugOverlays & OVERLAY_NPC_ZAP_BIT )
  400. {
  401. m_debugOverlays &= ~OVERLAY_NPC_ZAP_BIT;
  402. }
  403. BaseClass::DrawDebugGeometryOverlays();
  404. }
  405. //=======================================================================================
  406. // Furniture: A dumb "NPC" that is uses in scripted sequences
  407. // where an NPC needs to be frame locked with a prop.
  408. //=======================================================================================
  409. class CNPC_HearDanger : public CAI_BaseActor
  410. {
  411. DECLARE_CLASS( CNPC_HearDanger, CAI_BaseActor );
  412. DECLARE_DATADESC();
  413. public:
  414. void Spawn( void );
  415. void Precache( void );
  416. void Die( void );
  417. void UpdateEfficiency( bool bInPVS ) { SetEfficiency( ( GetSleepState() != AISS_AWAKE ) ? AIE_DORMANT : AIE_NORMAL ); SetMoveEfficiency( AIME_NORMAL ); }
  418. Class_T Classify( void );
  419. float MaxYawSpeed( void ){ return 0; }
  420. bool CreateVPhysics( void );
  421. int OnTakeDamage( const CTakeDamageInfo &info )
  422. {
  423. if ( m_iHealth <= info.GetDamage() )
  424. m_iHealth = info.GetDamage() + TOO_MUCH_HEALTH_TO_DIE;
  425. return BaseClass::OnTakeDamage( info );
  426. }
  427. void SetPlayerAvoidState( void );
  428. int GetSoundInterests( void );
  429. };
  430. LINK_ENTITY_TO_CLASS( npc_heardanger, CNPC_HearDanger );
  431. //-----------------------------------------------------------------------------
  432. // Save/load
  433. //-----------------------------------------------------------------------------
  434. BEGIN_DATADESC( CNPC_HearDanger )
  435. END_DATADESC()
  436. //-----------------------------------------------------------------------------
  437. // Purpose: This used to have something to do with bees flying, but
  438. // now it only initializes moving furniture in scripted sequences
  439. //-----------------------------------------------------------------------------
  440. void CNPC_HearDanger::Spawn()
  441. {
  442. Precache();
  443. SetModel( STRING( GetModelName() ) );
  444. SetMoveType( MOVETYPE_STEP );
  445. SetSolid( SOLID_BBOX );
  446. // Our collision, if needed, will be done through bone followers
  447. AddSolidFlags( FSOLID_NOT_SOLID );
  448. SetBloodColor( DONT_BLEED );
  449. m_iHealth = TOO_MUCH_HEALTH_TO_DIE; //wow
  450. m_takedamage = DAMAGE_AIM;
  451. SetSequence( 0 );
  452. SetCycle( 0 );
  453. SetNavType( NAV_FLY );
  454. AddFlag( FL_FLY );
  455. CapabilitiesAdd( bits_CAP_MOVE_FLY | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
  456. AddEFlags( EFL_NO_MEGAPHYSCANNON_RAGDOLL );
  457. SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR );
  458. // pev->nextthink += 1.0;
  459. // SetThink (WalkMonsterDelay);
  460. ResetSequenceInfo();
  461. SetCycle( 0 );
  462. NPCInit();
  463. // Furniture needs to block LOS
  464. SetBlocksLOS( false );
  465. // Furniture just wastes CPU doing sensing code, since all they do is idle and play scripts
  466. GetSenses()->AddSensingFlags( SENSING_FLAGS_DONT_LOOK );
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose:
  470. //-----------------------------------------------------------------------------
  471. void CNPC_HearDanger::Precache( void )
  472. {
  473. PrecacheModel( STRING( GetModelName() ) );
  474. }
  475. //=========================================================
  476. // GetSoundInterests - generic NPC can't hear.
  477. //=========================================================
  478. int CNPC_HearDanger::GetSoundInterests( void )
  479. {
  480. return SOUND_WORLD | SOUND_COMBAT | SOUND_PLAYER | SOUND_PLAYER_VEHICLE | SOUND_BULLET_IMPACT;
  481. }
  482. //-----------------------------------------------------------------------------
  483. // Purpose: Furniture is killed
  484. //-----------------------------------------------------------------------------
  485. void CNPC_HearDanger::Die( void )
  486. {
  487. SetThink( &CNPC_HearDanger::SUB_Remove );
  488. SetNextThink( gpGlobals->curtime );
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Purpose: ID's Furniture as neutral (noone will attack it)
  492. //-----------------------------------------------------------------------------
  493. Class_T CNPC_HearDanger::Classify( void )
  494. {
  495. return CLASS_NONE;
  496. }
  497. //------------------------------------------------------------------------------
  498. // Purpose:
  499. //------------------------------------------------------------------------------
  500. bool CNPC_HearDanger::CreateVPhysics( void )
  501. {
  502. return false;
  503. }
  504. void CNPC_HearDanger::SetPlayerAvoidState( void )
  505. {
  506. }