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.

469 lines
12 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 "shareddefs.h"
  13. #include "npcevent.h"
  14. #include "ai_basenpc.h"
  15. #include "ai_hull.h"
  16. #include "ai_baseactor.h"
  17. #include "tier1/strtools.h"
  18. #include "vstdlib/random.h"
  19. #include "engine/IEngineSound.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. ConVar flex_looktime( "flex_looktime", "5" );
  23. //---------------------------------------------------------
  24. // Sounds
  25. //---------------------------------------------------------
  26. //=========================================================
  27. // NPC's Anim Events Go Here
  28. //=========================================================
  29. class CGenericActor : public CAI_BaseActor
  30. {
  31. public:
  32. DECLARE_CLASS( CGenericActor, CAI_BaseActor );
  33. void Spawn( void );
  34. void Precache( void );
  35. float MaxYawSpeed( void );
  36. Class_T Classify ( void );
  37. void HandleAnimEvent( animevent_t *pEvent );
  38. int GetSoundInterests ( void );
  39. virtual int UpdateTransmitState( void );
  40. void TempGunEffect( void );
  41. string_t m_strHullName;
  42. DECLARE_DATADESC();
  43. };
  44. LINK_ENTITY_TO_CLASS( generic_actor, CGenericActor );
  45. BEGIN_DATADESC( CGenericActor )
  46. DEFINE_KEYFIELD(m_strHullName, FIELD_STRING, "hull_name" ),
  47. END_DATADESC()
  48. //=========================================================
  49. // Classify - indicates this NPC's place in the
  50. // relationship table.
  51. //=========================================================
  52. Class_T CGenericActor::Classify ( void )
  53. {
  54. return CLASS_NONE;
  55. }
  56. //=========================================================
  57. // MaxYawSpeed - allows each sequence to have a different
  58. // turn rate associated with it.
  59. //=========================================================
  60. float CGenericActor::MaxYawSpeed ( void )
  61. {
  62. return 90;
  63. }
  64. //=========================================================
  65. // HandleAnimEvent - catches the NPC-specific messages
  66. // that occur when tagged animation frames are played.
  67. //=========================================================
  68. void CGenericActor::HandleAnimEvent( animevent_t *pEvent )
  69. {
  70. BaseClass::HandleAnimEvent( pEvent );
  71. }
  72. //=========================================================
  73. // GetSoundInterests - generic NPC can't hear.
  74. //=========================================================
  75. int CGenericActor::GetSoundInterests ( void )
  76. {
  77. return NULL;
  78. }
  79. //=========================================================
  80. // Spawn
  81. //=========================================================
  82. void CGenericActor::Spawn()
  83. {
  84. Precache();
  85. SetModel( STRING( GetModelName() ) );
  86. /*
  87. if ( FStrEq( STRING( GetModelName() ), "models/player.mdl" ) )
  88. UTIL_SetSize(this, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
  89. else
  90. UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
  91. */
  92. if ( FStrEq( STRING( GetModelName() ), "models/player.mdl" ) ||
  93. FStrEq( STRING( GetModelName() ), "models/holo.mdl" ) ||
  94. FStrEq( STRING( GetModelName() ), "models/blackout.mdl" ) )
  95. {
  96. UTIL_SetSize(this, VEC_HULL_MIN, VEC_HULL_MAX);
  97. }
  98. else
  99. {
  100. UTIL_SetSize(this, NAI_Hull::Mins(HULL_HUMAN), NAI_Hull::Maxs(HULL_HUMAN));
  101. }
  102. if ( !FStrEq( STRING( GetModelName() ), "models/blackout.mdl" ) )
  103. {
  104. SetSolid( SOLID_BBOX );
  105. AddSolidFlags( FSOLID_NOT_STANDABLE );
  106. }
  107. else
  108. {
  109. SetSolid( SOLID_NONE );
  110. }
  111. SetMoveType( MOVETYPE_STEP );
  112. SetBloodColor( BLOOD_COLOR_RED );
  113. m_iHealth = 8;
  114. m_flFieldOfView = 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result )
  115. m_NPCState = NPC_STATE_NONE;
  116. CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS );
  117. // remove head turn if no eyes or forward attachment
  118. if (LookupAttachment( "eyes" ) > 0 && LookupAttachment( "forward" ) > 0)
  119. {
  120. CapabilitiesAdd( bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
  121. }
  122. if (m_strHullName != NULL_STRING)
  123. {
  124. SetHullType( NAI_Hull::LookupId( STRING( m_strHullName ) ) );
  125. }
  126. else
  127. {
  128. SetHullType( HULL_HUMAN );
  129. }
  130. SetHullSizeNormal( );
  131. NPCInit();
  132. }
  133. //=========================================================
  134. // Precache - precaches all resources this NPC needs
  135. //=========================================================
  136. void CGenericActor::Precache()
  137. {
  138. PrecacheModel( STRING( GetModelName() ) );
  139. }
  140. //=========================================================
  141. // Send to all clients since we need to drive the lighted mouth with this
  142. //=========================================================
  143. int CGenericActor::UpdateTransmitState()
  144. {
  145. // ALWAYS transmit to all clients.
  146. return SetTransmitState( FL_EDICT_ALWAYS );
  147. }
  148. //=========================================================
  149. // AI Schedules Specific to this NPC
  150. //=========================================================
  151. // -----------------------------------------------------------------------
  152. // FIXME: delete this code
  153. class CFlextalkActor : public CGenericActor
  154. {
  155. private:
  156. DECLARE_CLASS( CFlextalkActor, CGenericActor );
  157. public:
  158. DECLARE_DATADESC();
  159. CFlextalkActor() { m_iszSentence = NULL_STRING; m_sentence = 0; }
  160. //void GenericCyclerSpawn(char *szModel, Vector vecMin, Vector vecMax);
  161. //virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE); }
  162. //int OnTakeDamage( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType );
  163. //void Spawn( void );
  164. //void Precache( void );
  165. //void Think( void );
  166. virtual void ProcessSceneEvents( void );
  167. // Don't treat as a live target
  168. //virtual bool IsAlive( void ) { return FALSE; }
  169. float m_flextime;
  170. LocalFlexController_t m_flexnum;
  171. float m_flextarget[64];
  172. float m_blinktime;
  173. float m_looktime;
  174. Vector m_lookTarget;
  175. float m_speaktime;
  176. int m_istalking;
  177. int m_phoneme;
  178. string_t m_iszSentence;
  179. int m_sentence;
  180. void SetFlexTarget( LocalFlexController_t flexnum, float value );
  181. LocalFlexController_t LookupFlex( const char *szTarget );
  182. };
  183. BEGIN_DATADESC( CFlextalkActor )
  184. DEFINE_FIELD( m_flextime, FIELD_TIME ),
  185. DEFINE_FIELD( m_flexnum, FIELD_INTEGER ),
  186. DEFINE_ARRAY( m_flextarget, FIELD_FLOAT, 64 ),
  187. DEFINE_FIELD( m_blinktime, FIELD_TIME ),
  188. DEFINE_FIELD( m_looktime, FIELD_TIME ),
  189. DEFINE_FIELD( m_lookTarget, FIELD_POSITION_VECTOR ),
  190. DEFINE_FIELD( m_speaktime, FIELD_TIME ),
  191. DEFINE_FIELD( m_istalking, FIELD_INTEGER ),
  192. DEFINE_FIELD( m_phoneme, FIELD_INTEGER ),
  193. DEFINE_KEYFIELD( m_iszSentence, FIELD_STRING, "Sentence" ),
  194. DEFINE_FIELD( m_sentence, FIELD_INTEGER ),
  195. END_DATADESC()
  196. LINK_ENTITY_TO_CLASS( cycler_actor, CFlextalkActor );
  197. extern ConVar flex_expression;
  198. extern ConVar flex_talk;
  199. // Cycler member functions
  200. extern const char *predef_flexcontroller_names[];
  201. extern float predef_flexcontroller_values[7][30];
  202. void CFlextalkActor::SetFlexTarget( LocalFlexController_t flexnum, float value )
  203. {
  204. m_flextarget[flexnum] = value;
  205. const char *pszType = GetFlexControllerType( flexnum );
  206. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  207. {
  208. if (i != flexnum)
  209. {
  210. const char *pszOtherType = GetFlexControllerType( i );
  211. if (stricmp( pszType, pszOtherType ) == 0)
  212. {
  213. m_flextarget[i] = 0;
  214. }
  215. }
  216. }
  217. float value2 = value;
  218. if (1 || random->RandomFloat( 0.0, 1.0 ) < 0.2)
  219. {
  220. value2 = random->RandomFloat( value - 0.2, value + 0.2 );
  221. value2 = clamp( value2, 0.0, 1.0 );
  222. }
  223. // HACK, for now, consider then linked is named "right_" or "left_"
  224. if ( StringHasPrefixCaseSensitive( GetFlexControllerName( flexnum ), "right_" ) )
  225. {
  226. m_flextarget[flexnum+1] = value2;
  227. }
  228. else if ( StringHasPrefixCaseSensitive( GetFlexControllerName( flexnum ), "left_" ) )
  229. {
  230. m_flextarget[flexnum-1] = value2;
  231. }
  232. }
  233. LocalFlexController_t CFlextalkActor::LookupFlex( const char *szTarget )
  234. {
  235. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  236. {
  237. const char *pszFlex = GetFlexControllerName( i );
  238. if (stricmp( szTarget, pszFlex ) == 0)
  239. {
  240. return i;
  241. }
  242. }
  243. return LocalFlexController_t(-1);
  244. }
  245. void CFlextalkActor::ProcessSceneEvents( void )
  246. {
  247. if ( HasSceneEvents() )
  248. {
  249. BaseClass::ProcessSceneEvents( );
  250. return;
  251. }
  252. // only do this if they have more than eyelid movement
  253. if (GetNumFlexControllers() > 2)
  254. {
  255. const char *pszExpression = flex_expression.GetString();
  256. if (pszExpression && pszExpression[0] == '+' && pszExpression[1] != '\0')
  257. {
  258. int i;
  259. int j = atoi( &pszExpression[1] );
  260. for (i = 0; i < GetNumFlexControllers(); i++)
  261. {
  262. m_flextarget[m_flexnum] = 0;
  263. }
  264. for (i = 0; i < 35 && predef_flexcontroller_names[i]; i++)
  265. {
  266. m_flexnum = LookupFlex( predef_flexcontroller_names[i] );
  267. m_flextarget[m_flexnum] = predef_flexcontroller_values[j][i];
  268. // Msg( "%s %.3f\n", predef_flexcontroller_names[i], predef_flexcontroller_values[j][i] );
  269. }
  270. }
  271. else if (pszExpression && pszExpression[0] != '\0' && strcmp(pszExpression, "+") != 0)
  272. {
  273. char szExpression[128];
  274. char szTemp[32];
  275. Q_strncpy( szExpression, pszExpression ,sizeof(szExpression));
  276. char *pszExpression = szExpression;
  277. while (*pszExpression != '\0')
  278. {
  279. if (*pszExpression == '+')
  280. *pszExpression = ' ';
  281. pszExpression++;
  282. }
  283. pszExpression = szExpression;
  284. while (*pszExpression)
  285. {
  286. if (*pszExpression != ' ')
  287. {
  288. if (*pszExpression == '-')
  289. {
  290. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  291. {
  292. m_flextarget[i] = 0;
  293. }
  294. }
  295. else if (*pszExpression == '?')
  296. {
  297. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  298. {
  299. Msg( "\"%s\" ", GetFlexControllerName( i ) );
  300. }
  301. Msg( "\n" );
  302. flex_expression.SetValue( "" );
  303. }
  304. else
  305. {
  306. if (sscanf( pszExpression, "%31s", szTemp ) == 1)
  307. {
  308. m_flexnum = LookupFlex( szTemp );
  309. if (m_flexnum != -1 && m_flextarget[m_flexnum] != 1)
  310. {
  311. m_flextarget[m_flexnum] = 1.0;
  312. // SetFlexTarget( m_flexnum );
  313. }
  314. pszExpression += strlen( szTemp ) - 1;
  315. }
  316. }
  317. }
  318. pszExpression++;
  319. }
  320. }
  321. else if (m_flextime < gpGlobals->curtime)
  322. {
  323. m_flextime = gpGlobals->curtime + random->RandomFloat( 0.3, 0.5 ) * (30.0 / GetNumFlexControllers());
  324. m_flexnum = (LocalFlexController_t)random->RandomInt( 0, GetNumFlexControllers() - 1 );
  325. if (m_flextarget[m_flexnum] == 1)
  326. {
  327. m_flextarget[m_flexnum] = 0;
  328. }
  329. else if (stricmp( GetFlexControllerType( m_flexnum ), "phoneme" ) != 0)
  330. {
  331. if (strstr( GetFlexControllerName( m_flexnum ), "upper_raiser" ) == NULL)
  332. {
  333. Msg( "%s:%s\n", GetFlexControllerType( m_flexnum ), GetFlexControllerName( m_flexnum ) );
  334. SetFlexTarget( m_flexnum, random->RandomFloat( 0.5, 1.0 ) );
  335. }
  336. }
  337. }
  338. // slide it up.
  339. for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
  340. {
  341. float weight = GetFlexWeight( i );
  342. if (weight != m_flextarget[i])
  343. {
  344. weight = weight + (m_flextarget[i] - weight) / random->RandomFloat( 2.0, 4.0 );
  345. }
  346. weight = clamp( weight, 0.0f, 1.0f );
  347. SetFlexWeight( i, weight );
  348. }
  349. if (flex_talk.GetInt() == -1)
  350. {
  351. m_istalking = 1;
  352. char pszSentence[256];
  353. Q_snprintf( pszSentence,sizeof(pszSentence), "%s%d", STRING(m_iszSentence), m_sentence++ );
  354. int sentenceIndex = engine->SentenceIndexFromName( pszSentence );
  355. if (sentenceIndex >= 0)
  356. {
  357. Msg( "%d : %s\n", sentenceIndex, pszSentence );
  358. CPASAttenuationFilter filter( this );
  359. CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, SNDLVL_TALKING, 0, PITCH_NORM );
  360. }
  361. else
  362. {
  363. m_sentence = 0;
  364. }
  365. flex_talk.SetValue( "0" );
  366. }
  367. else if (flex_talk.GetInt() == -2)
  368. {
  369. m_flNextEyeLookTime = gpGlobals->curtime + 1000.0;
  370. }
  371. else if (flex_talk.GetInt() == -3)
  372. {
  373. m_flNextEyeLookTime = gpGlobals->curtime;
  374. flex_talk.SetValue( "0" );
  375. }
  376. else if (flex_talk.GetInt() == -4)
  377. {
  378. AddLookTarget( UTIL_PlayerByIndex( 1 ), 0.5, flex_looktime.GetFloat() );
  379. flex_talk.SetValue( "0" );
  380. }
  381. else if (flex_talk.GetInt() == -5)
  382. {
  383. PickLookTarget( true );
  384. flex_talk.SetValue( "0" );
  385. }
  386. }
  387. }