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.

272 lines
7.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Alyx, the female sidekick and love interest that's taking the world by storm!
  4. //
  5. // Try the new Alyx Brite toothpaste!
  6. // Alyx lederhosen!
  7. //
  8. // FIXME: need a better comment block
  9. //
  10. //=============================================================================//
  11. #include "cbase.h"
  12. #include "npcevent.h"
  13. #include "ai_basenpc.h"
  14. #include "ai_hull.h"
  15. #include "ai_basehumanoid.h"
  16. #include "npc_alyx.h"
  17. #include "ai_senses.h"
  18. #include "soundent.h"
  19. #include "props.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. LINK_ENTITY_TO_CLASS( npc_alyx, CNPC_Alyx );
  23. BEGIN_DATADESC( CNPC_Alyx )
  24. DEFINE_FIELD( m_hEmpTool, FIELD_EHANDLE ),
  25. END_DATADESC()
  26. int AE_ALYX_EMPTOOL_ATTACHMENT;
  27. int AE_ALYX_EMPTOOL_SEQUENCE;
  28. //=========================================================
  29. // Classify - indicates this NPC's place in the
  30. // relationship table.
  31. //=========================================================
  32. Class_T CNPC_Alyx::Classify ( void )
  33. {
  34. return CLASS_PLAYER_ALLY_VITAL;
  35. }
  36. //=========================================================
  37. // HandleAnimEvent - catches the NPC-specific messages
  38. // that occur when tagged animation frames are played.
  39. //=========================================================
  40. void CNPC_Alyx::HandleAnimEvent( animevent_t *pEvent )
  41. {
  42. if (pEvent->event == AE_ALYX_EMPTOOL_ATTACHMENT)
  43. {
  44. if (!m_hEmpTool)
  45. {
  46. // Old savegame?
  47. CreateEmpTool();
  48. if (!m_hEmpTool)
  49. return;
  50. }
  51. int iAttachment = LookupAttachment( pEvent->options );
  52. m_hEmpTool->SetParent(this, iAttachment);
  53. m_hEmpTool->SetLocalOrigin( Vector( 0, 0, 0 ) );
  54. m_hEmpTool->SetLocalAngles( QAngle( 0, 0, 0 ) );
  55. return;
  56. }
  57. else if (pEvent->event == AE_ALYX_EMPTOOL_SEQUENCE)
  58. {
  59. if (!m_hEmpTool)
  60. return;
  61. CDynamicProp *pEmpTool = dynamic_cast<CDynamicProp *>(m_hEmpTool.Get());
  62. if (!pEmpTool)
  63. return;
  64. int iSequence = pEmpTool->LookupSequence( pEvent->options );
  65. if (iSequence != ACT_INVALID)
  66. {
  67. pEmpTool->PropSetSequence( iSequence );
  68. }
  69. return;
  70. }
  71. switch( pEvent->event )
  72. {
  73. case 1:
  74. default:
  75. BaseClass::HandleAnimEvent( pEvent );
  76. break;
  77. }
  78. }
  79. //=========================================================
  80. //
  81. //=========================================================
  82. bool CNPC_Alyx::CreateBehaviors()
  83. {
  84. return BaseClass::CreateBehaviors();
  85. }
  86. //=========================================================
  87. // Spawn
  88. //=========================================================
  89. void CNPC_Alyx::Spawn()
  90. {
  91. BaseClass::Spawn();
  92. // If Alyx has a parent, she's currently inside a pod. Prevent her from moving.
  93. if ( GetMoveParent() )
  94. {
  95. SetMoveType( MOVETYPE_NONE );
  96. CapabilitiesClear();
  97. CapabilitiesAdd( bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD );
  98. CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
  99. }
  100. else
  101. {
  102. SetupAlyxWithoutParent();
  103. CreateEmpTool( );
  104. }
  105. AddEFlags( EFL_NO_DISSOLVE | EFL_NO_MEGAPHYSCANNON_RAGDOLL | EFL_NO_PHYSCANNON_INTERACTION );
  106. m_iHealth = 80;
  107. NPCInit();
  108. }
  109. //=========================================================
  110. // Precache - precaches all resources this NPC needs
  111. //=========================================================
  112. void CNPC_Alyx::Precache()
  113. {
  114. BaseClass::Precache();
  115. PrecacheScriptSound( "npc_alyx.die" );
  116. PrecacheModel( STRING( GetModelName() ) );
  117. PrecacheModel( "models/alyx_emptool_prop.mdl" );
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose:
  121. //-----------------------------------------------------------------------------
  122. void CNPC_Alyx::SelectModel()
  123. {
  124. // Alyx is allowed to use multiple models, because she appears in the pod.
  125. // She defaults to her normal model.
  126. const char *szModel = STRING( GetModelName() );
  127. if (!szModel || !*szModel)
  128. {
  129. SetModelName( AllocPooledString("models/alyx.mdl") );
  130. }
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. //-----------------------------------------------------------------------------
  135. void CNPC_Alyx::SetupAlyxWithoutParent( void )
  136. {
  137. SetSolid( SOLID_BBOX );
  138. AddSolidFlags( FSOLID_NOT_STANDABLE );
  139. SetMoveType( MOVETYPE_STEP );
  140. CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_DOORS_GROUP | bits_CAP_TURN_HEAD | bits_CAP_DUCK | bits_CAP_SQUAD );
  141. CapabilitiesAdd( bits_CAP_USE_WEAPONS );
  142. CapabilitiesAdd( bits_CAP_ANIMATEDFACE );
  143. CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
  144. CapabilitiesAdd( bits_CAP_AIM_GUN );
  145. CapabilitiesAdd( bits_CAP_MOVE_SHOOT );
  146. CapabilitiesAdd( bits_CAP_USE_SHOT_REGULATOR );
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. //-----------------------------------------------------------------------------
  151. void CNPC_Alyx::CreateEmpTool( void )
  152. {
  153. m_hEmpTool = (CBaseAnimating*)CreateEntityByName( "prop_dynamic" );
  154. if ( m_hEmpTool )
  155. {
  156. m_hEmpTool->SetModel( "models/alyx_emptool_prop.mdl" );
  157. m_hEmpTool->SetName( AllocPooledString("Alyx_Emptool") );
  158. int iAttachment = LookupAttachment( "Emp_Holster" );
  159. m_hEmpTool->SetParent(this, iAttachment);
  160. m_hEmpTool->SetOwnerEntity(this);
  161. m_hEmpTool->SetSolid( SOLID_NONE );
  162. m_hEmpTool->SetLocalOrigin( Vector( 0, 0, 0 ) );
  163. m_hEmpTool->SetLocalAngles( QAngle( 0, 0, 0 ) );
  164. m_hEmpTool->Spawn();
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. void CNPC_Alyx::PrescheduleThink( void )
  171. {
  172. BaseClass::PrescheduleThink();
  173. // Figure out if Alyx has just been removed from her parent
  174. if ( GetMoveType() == MOVETYPE_NONE && !GetMoveParent() )
  175. {
  176. SetupAlyxWithoutParent();
  177. SetupVPhysicsHull();
  178. }
  179. if ( HasCondition( COND_TALKER_PLAYER_DEAD ) )
  180. {
  181. SpeakIfAllowed( TLK_PLDEAD );
  182. }
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose:
  186. //-----------------------------------------------------------------------------
  187. Activity CNPC_Alyx::NPC_TranslateActivity( Activity activity )
  188. {
  189. activity = BaseClass::NPC_TranslateActivity( activity );
  190. if ( activity == ACT_IDLE && (m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT) )
  191. {
  192. if (gpGlobals->curtime - m_flLastAttackTime < 3 || gpGlobals->curtime - GetEnemyLastTimeSeen() < 8)
  193. {
  194. activity = ACT_IDLE_ANGRY;
  195. }
  196. }
  197. return activity;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose:
  201. //-----------------------------------------------------------------------------
  202. void CNPC_Alyx::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
  203. {
  204. BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
  205. // FIXME: hack until some way of removing decals after healing
  206. m_fNoDamageDecal = true;
  207. }
  208. //-----------------------------------------------------------------------------
  209. void CNPC_Alyx::DeathSound( const CTakeDamageInfo &info )
  210. {
  211. // Sentences don't play on dead NPCs
  212. SentenceStop();
  213. EmitSound( "npc_alyx.die" );
  214. }
  215. //=========================================================
  216. // AI Schedules Specific to this NPC
  217. //=========================================================
  218. AI_BEGIN_CUSTOM_NPC( npc_alyx, CNPC_Alyx )
  219. DECLARE_ANIMEVENT( AE_ALYX_EMPTOOL_ATTACHMENT )
  220. DECLARE_ANIMEVENT( AE_ALYX_EMPTOOL_SEQUENCE )
  221. AI_END_CUSTOM_NPC()