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.

215 lines
5.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "hl1_ai_basenpc.h"
  10. #include "scripted.h"
  11. #include "soundent.h"
  12. #include "animation.h"
  13. #include "entitylist.h"
  14. #include "ai_navigator.h"
  15. #include "ai_motor.h"
  16. #include "player.h"
  17. #include "vstdlib/random.h"
  18. #include "engine/IEngineSound.h"
  19. #include "npcevent.h"
  20. #include "effect_dispatch_data.h"
  21. #include "te_effect_dispatch.h"
  22. #include "cplane.h"
  23. #include "ai_squad.h"
  24. #define HUMAN_GIBS 1
  25. #define ALIEN_GIBS 2
  26. //=========================================================
  27. // NoFriendlyFire - checks for possibility of friendly fire
  28. //
  29. // Builds a large box in front of the grunt and checks to see
  30. // if any squad members are in that box.
  31. //=========================================================
  32. bool CHL1BaseNPC::NoFriendlyFire( void )
  33. {
  34. if ( !m_pSquad )
  35. {
  36. return true;
  37. }
  38. CPlane backPlane;
  39. CPlane leftPlane;
  40. CPlane rightPlane;
  41. Vector vecLeftSide;
  42. Vector vecRightSide;
  43. Vector v_left;
  44. Vector vForward, vRight, vUp;
  45. QAngle vAngleToEnemy;
  46. if ( GetEnemy() != NULL )
  47. {
  48. //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!!
  49. VectorAngles( ( GetEnemy()->WorldSpaceCenter() - GetAbsOrigin() ), vAngleToEnemy );
  50. AngleVectors ( vAngleToEnemy, &vForward, &vRight, &vUp );
  51. }
  52. else
  53. {
  54. // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot.
  55. return false;
  56. }
  57. vecLeftSide = GetAbsOrigin() - ( vRight * ( WorldAlignSize().x * 1.5 ) );
  58. vecRightSide = GetAbsOrigin() + ( vRight * ( WorldAlignSize().x * 1.5 ) );
  59. v_left = vRight * -1;
  60. leftPlane.InitializePlane ( vRight, vecLeftSide );
  61. rightPlane.InitializePlane ( v_left, vecRightSide );
  62. backPlane.InitializePlane ( vForward, GetAbsOrigin() );
  63. AISquadIter_t iter;
  64. for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
  65. {
  66. if ( pSquadMember == NULL )
  67. continue;
  68. if ( pSquadMember == this )
  69. continue;
  70. if ( backPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) &&
  71. leftPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) &&
  72. rightPlane.PointInFront ( pSquadMember->GetAbsOrigin()) )
  73. {
  74. // this guy is in the check volume! Don't shoot!
  75. return false;
  76. }
  77. }
  78. return true;
  79. }
  80. void CHL1BaseNPC::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
  81. {
  82. if ( info.GetDamage() >= 1.0 && !(info.GetDamageType() & DMG_SHOCK ) )
  83. {
  84. UTIL_BloodSpray( ptr->endpos, vecDir, BloodColor(), 4, FX_BLOODSPRAY_ALL );
  85. }
  86. BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
  87. }
  88. bool CHL1BaseNPC::ShouldGib( const CTakeDamageInfo &info )
  89. {
  90. if ( info.GetDamageType() & DMG_NEVERGIB )
  91. return false;
  92. if ( ( g_pGameRules->Damage_ShouldGibCorpse( info.GetDamageType() ) && m_iHealth < GIB_HEALTH_VALUE ) || ( info.GetDamageType() & DMG_ALWAYSGIB ) )
  93. return true;
  94. return false;
  95. }
  96. bool CHL1BaseNPC::HasHumanGibs( void )
  97. {
  98. Class_T myClass = Classify();
  99. if ( myClass == CLASS_HUMAN_MILITARY ||
  100. myClass == CLASS_PLAYER_ALLY ||
  101. myClass == CLASS_HUMAN_PASSIVE ||
  102. myClass == CLASS_PLAYER )
  103. return true;
  104. return false;
  105. }
  106. bool CHL1BaseNPC::HasAlienGibs( void )
  107. {
  108. Class_T myClass = Classify();
  109. if ( myClass == CLASS_ALIEN_MILITARY ||
  110. myClass == CLASS_ALIEN_MONSTER ||
  111. myClass == CLASS_INSECT ||
  112. myClass == CLASS_ALIEN_PREDATOR ||
  113. myClass == CLASS_ALIEN_PREY )
  114. return true;
  115. return false;
  116. }
  117. void CHL1BaseNPC::Precache( void )
  118. {
  119. PrecacheModel( "models/gibs/agibs.mdl" );
  120. PrecacheModel( "models/gibs/hgibs.mdl" );
  121. BaseClass::Precache();
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. // Output : Returns true on success, false on failure.
  126. //-----------------------------------------------------------------------------
  127. bool CHL1BaseNPC::CorpseGib( const CTakeDamageInfo &info )
  128. {
  129. CEffectData data;
  130. data.m_vOrigin = WorldSpaceCenter();
  131. data.m_vNormal = data.m_vOrigin - info.GetDamagePosition();
  132. VectorNormalize( data.m_vNormal );
  133. data.m_flScale = RemapVal( m_iHealth, 0, -500, 1, 3 );
  134. data.m_flScale = clamp( data.m_flScale, 1, 3 );
  135. if ( HasAlienGibs() )
  136. data.m_nMaterial = ALIEN_GIBS;
  137. else if ( HasHumanGibs() )
  138. data.m_nMaterial = HUMAN_GIBS;
  139. data.m_nColor = BloodColor();
  140. DispatchEffect( "HL1Gib", data );
  141. CSoundEnt::InsertSound( SOUND_MEAT, GetAbsOrigin(), 256, 0.5f, this );
  142. /// BaseClass::CorpseGib( info );
  143. return true;
  144. }
  145. int CHL1BaseNPC::IRelationPriority( CBaseEntity *pTarget )
  146. {
  147. return BaseClass::IRelationPriority( pTarget );
  148. }
  149. void CHL1BaseNPC::EjectShell( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int iType )
  150. {
  151. CEffectData data;
  152. data.m_vStart = vecVelocity;
  153. data.m_vOrigin = vecOrigin;
  154. data.m_vAngles = QAngle( 0, rotation, 0 );
  155. data.m_fFlags = iType;
  156. DispatchEffect( "HL1ShellEject", data );
  157. }
  158. // HL1 version - never return Ragdoll as the automatic schedule at the end of a
  159. // scripted sequence
  160. int CHL1BaseNPC::SelectDeadSchedule()
  161. {
  162. // Alread dead (by animation event maybe?)
  163. // Is it safe to set it to SCHED_NONE?
  164. if ( m_lifeState == LIFE_DEAD )
  165. return SCHED_NONE;
  166. CleanupOnDeath();
  167. return SCHED_DIE;
  168. }