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.

542 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "baseanimating.h"
  9. #include "Sprite.h"
  10. #include "SpriteTrail.h"
  11. #include <ctype.h>
  12. #include "animation.h"
  13. #include "eventlist.h"
  14. #include "npcevent.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. enum EffectType
  18. {
  19. EFFECT_TYPE_TRAIL = 1,
  20. EFFECT_TYPE_SPRITE
  21. };
  22. bool g_bUnget = false;
  23. unsigned char *buffer;
  24. char name[ 256 ];
  25. const char *currenttoken;
  26. int tokencount;
  27. char token[ 1204 ];
  28. class CEffectScriptElement
  29. {
  30. public:
  31. CEffectScriptElement();
  32. char m_szEffectName[128];
  33. CHandle<CSpriteTrail> m_pTrail;
  34. CHandle<CSprite> m_pSprite;
  35. int m_iType;
  36. int m_iRenderType;
  37. int m_iR;
  38. int m_iG;
  39. int m_iB;
  40. int m_iA;
  41. char m_szAttachment[128];
  42. char m_szMaterial[128];
  43. float m_flScale;
  44. float m_flFadeTime;
  45. float m_flTextureRes;
  46. bool m_bStopFollowOnKill;
  47. bool IsActive( void ) { return m_bActive; }
  48. void Activate( void ) { m_bActive = true; }
  49. void Deactivate( void ) { m_bActive = false; }
  50. private:
  51. bool m_bActive;
  52. };
  53. CEffectScriptElement::CEffectScriptElement()
  54. {
  55. m_pTrail = NULL;
  56. m_pSprite = NULL;
  57. m_iType = 0;
  58. Deactivate();
  59. m_iRenderType = kRenderTransAdd;
  60. m_iR = 255;
  61. m_iG = 0;
  62. m_iB = 0;
  63. m_iA = 255;
  64. m_flScale = 1.0f;
  65. m_flFadeTime = 1.0f;
  66. m_flTextureRes = -1.0f;
  67. m_bStopFollowOnKill = false;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // An entity which emits other entities at points
  71. //-----------------------------------------------------------------------------
  72. class CEnvEffectsScript : public CBaseAnimating
  73. {
  74. public:
  75. DECLARE_CLASS( CEnvEffectsScript, CBaseAnimating );
  76. DECLARE_DATADESC();
  77. virtual void Precache();
  78. virtual void Spawn();
  79. virtual int UpdateTransmitState();
  80. void InputSetSequence( inputdata_t &inputdata );
  81. void ParseScriptFile( void );
  82. void LoadFromBuffer( const char *scriptfile, const char *buffer );
  83. virtual void Think( void );
  84. void ParseNewEffect( void );
  85. const char *GetScriptFile( void )
  86. {
  87. return STRING( m_iszScriptName );
  88. }
  89. void HandleAnimEvent ( animevent_t *pEvent );
  90. void TrailEffectEvent( CEffectScriptElement *pEffect );
  91. void SpriteEffectEvent( CEffectScriptElement *pEffect );
  92. CEffectScriptElement *GetScriptElementByName( const char *pName );
  93. private:
  94. string_t m_iszScriptName;
  95. CUtlVector< CEffectScriptElement > m_ScriptElements;
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. // Output : Returns true on success, false on failure.
  99. //-----------------------------------------------------------------------------
  100. bool IsRootCommand( void )
  101. {
  102. if ( !Q_stricmp( token, "effect" ) )
  103. return true;
  104. return false;
  105. }
  106. };
  107. inline bool ParseToken( void )
  108. {
  109. if ( g_bUnget )
  110. {
  111. g_bUnget = false;
  112. return true;
  113. }
  114. currenttoken = engine->ParseFile( currenttoken, token, sizeof( token ) );
  115. tokencount++;
  116. return currenttoken != NULL ? true : false;
  117. }
  118. inline void Unget()
  119. {
  120. g_bUnget = true;
  121. }
  122. inline bool TokenWaiting( void )
  123. {
  124. const char *p = currenttoken;
  125. while ( *p && *p!='\n')
  126. {
  127. // Special handler for // comment blocks
  128. if ( *p == '/' && *(p+1) == '/' )
  129. return false;
  130. if ( !V_isspace( *p ) || V_isalnum( *p ) )
  131. return true;
  132. p++;
  133. }
  134. return false;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Save/load
  138. //-----------------------------------------------------------------------------
  139. BEGIN_DATADESC( CEnvEffectsScript )
  140. // Inputs
  141. DEFINE_INPUTFUNC( FIELD_STRING, "SetSequence", InputSetSequence ),
  142. DEFINE_KEYFIELD( m_iszScriptName, FIELD_STRING, "scriptfile" ),
  143. // DEFINE_FIELD( m_ScriptElements, CUtlVector < CEffectScriptElement > ),
  144. DEFINE_FUNCTION( Think ),
  145. END_DATADESC()
  146. LINK_ENTITY_TO_CLASS( env_effectscript, CEnvEffectsScript );
  147. //-----------------------------------------------------------------------------
  148. // Should we transmit it to the client?
  149. //-----------------------------------------------------------------------------
  150. int CEnvEffectsScript::UpdateTransmitState()
  151. {
  152. return SetTransmitState( FL_EDICT_ALWAYS );
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Precache
  156. //-----------------------------------------------------------------------------
  157. void CEnvEffectsScript::Precache()
  158. {
  159. BaseClass::Precache();
  160. PrecacheModel( STRING( GetModelName() ) );
  161. if ( m_iszScriptName != NULL_STRING )
  162. ParseScriptFile();
  163. else
  164. Warning( "CEnvEffectsScript with no script!\n" );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Spawn
  168. //-----------------------------------------------------------------------------
  169. void CEnvEffectsScript::Spawn()
  170. {
  171. Precache();
  172. BaseClass::Spawn();
  173. // We need a model for its animation sequences even though we don't render it
  174. SetModel( STRING( GetModelName() ) );
  175. AddEffects( EF_NODRAW );
  176. SetThink( &CEnvEffectsScript::Think );
  177. SetNextThink( gpGlobals->curtime + 0.1f );
  178. }
  179. void CEnvEffectsScript::Think( void )
  180. {
  181. StudioFrameAdvance();
  182. DispatchAnimEvents( this );
  183. SetNextThink( gpGlobals->curtime + 0.1f );
  184. }
  185. void CEnvEffectsScript::TrailEffectEvent( CEffectScriptElement *pEffect )
  186. {
  187. if ( pEffect->IsActive() == false )
  188. {
  189. //Only one type of this effect active at a time.
  190. if ( pEffect->m_pTrail == NULL )
  191. {
  192. pEffect->m_pTrail = CSpriteTrail::SpriteTrailCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
  193. pEffect->m_pTrail->FollowEntity( this );
  194. pEffect->m_pTrail->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
  195. pEffect->m_pTrail->SetStartWidth( pEffect->m_flScale );
  196. if ( pEffect->m_flTextureRes < 0.0f )
  197. {
  198. pEffect->m_pTrail->SetTextureResolution( 1.0f / ( 16.0f * pEffect->m_flScale ) );
  199. }
  200. else
  201. {
  202. pEffect->m_pTrail->SetTextureResolution( pEffect->m_flTextureRes );
  203. }
  204. pEffect->m_pTrail->SetLifeTime( pEffect->m_flFadeTime );
  205. pEffect->m_pTrail->TurnOn();
  206. pEffect->m_pTrail->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
  207. pEffect->Activate();
  208. }
  209. }
  210. }
  211. void CEnvEffectsScript::SpriteEffectEvent( CEffectScriptElement *pEffect )
  212. {
  213. if ( pEffect->IsActive() == false )
  214. {
  215. //Only one type of this effect active at a time.
  216. if ( pEffect->m_pSprite == NULL )
  217. {
  218. pEffect->m_pSprite = CSprite::SpriteCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
  219. pEffect->m_pSprite->FollowEntity( this );
  220. pEffect->m_pSprite->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
  221. pEffect->m_pSprite->SetScale( pEffect->m_flScale );
  222. pEffect->m_pSprite->TurnOn();
  223. pEffect->m_pSprite->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
  224. pEffect->Activate();
  225. }
  226. }
  227. }
  228. void CEnvEffectsScript::HandleAnimEvent ( animevent_t *pEvent )
  229. {
  230. if ( pEvent->event == AE_START_SCRIPTED_EFFECT )
  231. {
  232. CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
  233. if ( pCurrent )
  234. {
  235. if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
  236. TrailEffectEvent( pCurrent );
  237. else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
  238. SpriteEffectEvent( pCurrent );
  239. }
  240. return;
  241. }
  242. if ( pEvent->event == AE_STOP_SCRIPTED_EFFECT )
  243. {
  244. CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
  245. if ( pCurrent && pCurrent->IsActive() )
  246. {
  247. pCurrent->Deactivate();
  248. if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
  249. {
  250. if ( pCurrent->m_bStopFollowOnKill == true )
  251. {
  252. Vector vOrigin;
  253. GetAttachment( pCurrent->m_pTrail->m_nAttachment, vOrigin );
  254. pCurrent->m_pTrail->StopFollowingEntity();
  255. pCurrent->m_pTrail->m_hAttachedToEntity = NULL;
  256. pCurrent->m_pTrail->m_nAttachment = 0;
  257. pCurrent->m_pTrail->SetAbsOrigin( vOrigin);
  258. }
  259. pCurrent->m_pTrail->FadeAndDie( pCurrent->m_flFadeTime );
  260. pCurrent->m_pTrail = NULL;
  261. }
  262. else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
  263. {
  264. if ( pCurrent->m_bStopFollowOnKill == true )
  265. {
  266. Vector vOrigin;
  267. GetAttachment( pCurrent->m_pSprite->m_nAttachment, vOrigin );
  268. pCurrent->m_pSprite->StopFollowingEntity();
  269. pCurrent->m_pSprite->m_hAttachedToEntity = NULL;
  270. pCurrent->m_pSprite->m_nAttachment = 0;
  271. pCurrent->m_pSprite->SetAbsOrigin( vOrigin);
  272. }
  273. pCurrent->m_pSprite->FadeAndDie( pCurrent->m_flFadeTime );
  274. pCurrent->m_pSprite = NULL;
  275. }
  276. }
  277. return;
  278. }
  279. BaseClass::HandleAnimEvent( pEvent );
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Input that sets the sequence of the entity
  283. //-----------------------------------------------------------------------------
  284. void CEnvEffectsScript::InputSetSequence( inputdata_t &inputdata )
  285. {
  286. if ( inputdata.value.StringID() != NULL_STRING )
  287. {
  288. int nSequence = LookupSequence( STRING( inputdata.value.StringID() ) );
  289. if ( nSequence != ACT_INVALID )
  290. {
  291. SetSequence( nSequence );
  292. ResetSequenceInfo();
  293. SetCycle( 0.0f );
  294. m_flPlaybackRate = 1.0f;
  295. }
  296. }
  297. }
  298. void CEnvEffectsScript::ParseScriptFile( void )
  299. {
  300. int length = 0;
  301. m_ScriptElements.RemoveAll();
  302. const char *pScriptName = GetScriptFile();
  303. //Reset everything.
  304. g_bUnget = false;
  305. currenttoken = NULL;
  306. tokencount = 0;
  307. memset( token, 0, 1204 );
  308. memset( name, 0, 256 );
  309. unsigned char *buffer = (unsigned char *)UTIL_LoadFileForMe( pScriptName, &length );
  310. if ( length <= 0 || !buffer )
  311. {
  312. DevMsg( 1, "CEnvEffectsScript: failed to load %s\n", pScriptName );
  313. return;
  314. }
  315. currenttoken = (const char *)buffer;
  316. LoadFromBuffer( pScriptName, (const char *)buffer );
  317. UTIL_FreeFile( buffer );
  318. }
  319. void CEnvEffectsScript::LoadFromBuffer( const char *scriptfile, const char *buffer )
  320. {
  321. while ( 1 )
  322. {
  323. ParseToken();
  324. if ( !token[0] )
  325. {
  326. break;
  327. }
  328. if ( !Q_stricmp( token, "effect" ) )
  329. {
  330. ParseNewEffect();
  331. }
  332. else
  333. {
  334. Warning( "CEnvEffectsScript: Unknown entry type '%s'\n", token );
  335. break;
  336. }
  337. }
  338. }
  339. void CEnvEffectsScript::ParseNewEffect( void )
  340. {
  341. //Add a new effect to the list.
  342. CEffectScriptElement NewElement;
  343. // Effect Group Name
  344. ParseToken();
  345. Q_strncpy( NewElement.m_szEffectName, token, sizeof( NewElement.m_szEffectName ) );
  346. while ( 1 )
  347. {
  348. ParseToken();
  349. // Oops, part of next definition
  350. if( IsRootCommand() )
  351. {
  352. Unget();
  353. break;
  354. }
  355. if ( !Q_stricmp( token, "{" ) )
  356. {
  357. while ( 1 )
  358. {
  359. ParseToken();
  360. if ( !Q_stricmp( token, "}" ) )
  361. break;
  362. if ( !Q_stricmp( token, "type" ) )
  363. {
  364. ParseToken();
  365. if ( !Q_stricmp( token, "trail" ) )
  366. NewElement.m_iType = EFFECT_TYPE_TRAIL;
  367. else if ( !Q_stricmp( token, "sprite" ) )
  368. NewElement.m_iType = EFFECT_TYPE_SPRITE;
  369. continue;
  370. }
  371. if ( !Q_stricmp( token, "material" ) )
  372. {
  373. ParseToken();
  374. Q_strncpy( NewElement.m_szMaterial, token, sizeof( NewElement.m_szMaterial ) );
  375. PrecacheModel( NewElement.m_szMaterial );
  376. continue;
  377. }
  378. if ( !Q_stricmp( token, "attachment" ) )
  379. {
  380. ParseToken();
  381. Q_strncpy( NewElement.m_szAttachment, token, sizeof( NewElement.m_szAttachment ) );
  382. continue;
  383. }
  384. if ( !Q_stricmp( token, "color" ) )
  385. {
  386. ParseToken();
  387. sscanf( token, "%i %i %i %i", &NewElement.m_iR, &NewElement.m_iG, &NewElement.m_iB, &NewElement.m_iA );
  388. continue;
  389. }
  390. if ( !Q_stricmp( token, "scale" ) )
  391. {
  392. ParseToken();
  393. NewElement.m_flScale = atof( token );
  394. continue;
  395. }
  396. if ( !Q_stricmp( token, "texturescale" ) )
  397. {
  398. ParseToken();
  399. float flTextureScale = atof( token );
  400. NewElement.m_flTextureRes = (flTextureScale > 0.0f) ? 1.0f / flTextureScale : 0.0f;
  401. continue;
  402. }
  403. if ( !Q_stricmp( token, "fadetime" ) )
  404. {
  405. ParseToken();
  406. NewElement.m_flFadeTime = atof( token );
  407. continue;
  408. }
  409. if ( !Q_stricmp( token, "stopfollowonkill" ) )
  410. {
  411. ParseToken();
  412. NewElement.m_bStopFollowOnKill = !!atoi( token );
  413. continue;
  414. }
  415. }
  416. break;
  417. }
  418. }
  419. m_ScriptElements.AddToTail( NewElement );
  420. }
  421. CEffectScriptElement *CEnvEffectsScript::GetScriptElementByName( const char *pName )
  422. {
  423. for ( int i = 0; i < m_ScriptElements.Count(); i++ )
  424. {
  425. CEffectScriptElement *pCurrent = &m_ScriptElements.Element( i );
  426. if ( pCurrent && !Q_stricmp( pCurrent->m_szEffectName, pName ) )
  427. {
  428. return pCurrent;
  429. }
  430. }
  431. return NULL;
  432. }