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.

389 lines
12 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
  4. //
  5. // 1) An entity that can be placed by a level designer and triggered
  6. // to ignite a target entity.
  7. //
  8. // 2) An entity that can be created at runtime to ignite a target entity.
  9. //
  10. //=============================================================================//
  11. #include "cbase.h"
  12. #include "EntityDissolve.h"
  13. #include "baseanimating.h"
  14. #include "physics_prop_ragdoll.h"
  15. #include "ai_basenpc.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. static const char *s_pElectroThinkContext = "ElectroThinkContext";
  19. //-----------------------------------------------------------------------------
  20. // Lifetime
  21. //-----------------------------------------------------------------------------
  22. #define DISSOLVE_FADE_IN_START_TIME 0.0f
  23. #define DISSOLVE_FADE_IN_END_TIME 1.0f
  24. #define DISSOLVE_FADE_OUT_MODEL_START_TIME 1.9f
  25. #define DISSOLVE_FADE_OUT_MODEL_END_TIME 2.0f
  26. #define DISSOLVE_FADE_OUT_START_TIME 2.0f
  27. #define DISSOLVE_FADE_OUT_END_TIME 2.0f
  28. //-----------------------------------------------------------------------------
  29. // Model
  30. //-----------------------------------------------------------------------------
  31. #define DISSOLVE_SPRITE_NAME "sprites/blueglow1.vmt"
  32. //-----------------------------------------------------------------------------
  33. // Save/load
  34. //-----------------------------------------------------------------------------
  35. BEGIN_DATADESC( CEntityDissolve )
  36. DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
  37. DEFINE_FIELD( m_flFadeInStart, FIELD_FLOAT ),
  38. DEFINE_FIELD( m_flFadeInLength, FIELD_FLOAT ),
  39. DEFINE_FIELD( m_flFadeOutModelStart, FIELD_FLOAT ),
  40. DEFINE_FIELD( m_flFadeOutModelLength, FIELD_FLOAT ),
  41. DEFINE_FIELD( m_flFadeOutStart, FIELD_FLOAT ),
  42. DEFINE_FIELD( m_flFadeOutLength, FIELD_FLOAT ),
  43. DEFINE_KEYFIELD( m_nDissolveType, FIELD_INTEGER, "dissolvetype" ),
  44. DEFINE_FIELD( m_vDissolverOrigin, FIELD_VECTOR ),
  45. DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "magnitude" ),
  46. DEFINE_FUNCTION( DissolveThink ),
  47. DEFINE_FUNCTION( ElectrocuteThink ),
  48. DEFINE_INPUTFUNC( FIELD_STRING, "Dissolve", InputDissolve ),
  49. END_DATADESC()
  50. //-----------------------------------------------------------------------------
  51. // Networking
  52. //-----------------------------------------------------------------------------
  53. IMPLEMENT_SERVERCLASS_ST( CEntityDissolve, DT_EntityDissolve )
  54. SendPropTime( SENDINFO( m_flStartTime ) ),
  55. SendPropFloat( SENDINFO( m_flFadeInStart ), 0, SPROP_NOSCALE ),
  56. SendPropFloat( SENDINFO( m_flFadeInLength ), 0, SPROP_NOSCALE ),
  57. SendPropFloat( SENDINFO( m_flFadeOutModelStart ), 0, SPROP_NOSCALE ),
  58. SendPropFloat( SENDINFO( m_flFadeOutModelLength ), 0, SPROP_NOSCALE ),
  59. SendPropFloat( SENDINFO( m_flFadeOutStart ), 0, SPROP_NOSCALE ),
  60. SendPropFloat( SENDINFO( m_flFadeOutLength ), 0, SPROP_NOSCALE ),
  61. SendPropInt( SENDINFO( m_nDissolveType ), ENTITY_DISSOLVE_BITS, SPROP_UNSIGNED ),
  62. SendPropVector (SENDINFO(m_vDissolverOrigin), 0, SPROP_NOSCALE ),
  63. SendPropInt( SENDINFO( m_nMagnitude ), 8, SPROP_UNSIGNED ),
  64. END_SEND_TABLE()
  65. LINK_ENTITY_TO_CLASS( env_entity_dissolver, CEntityDissolve );
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. CEntityDissolve::CEntityDissolve( void )
  70. {
  71. m_flStartTime = 0.0f;
  72. m_nMagnitude = 250;
  73. }
  74. CEntityDissolve::~CEntityDissolve( void )
  75. {
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Precache
  79. //-----------------------------------------------------------------------------
  80. void CEntityDissolve::Precache()
  81. {
  82. if ( NULL_STRING == GetModelName() )
  83. {
  84. PrecacheModel( DISSOLVE_SPRITE_NAME );
  85. }
  86. else
  87. {
  88. PrecacheModel( STRING( GetModelName() ) );
  89. }
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Spawn
  93. //-----------------------------------------------------------------------------
  94. void CEntityDissolve::Spawn()
  95. {
  96. BaseClass::Spawn();
  97. Precache();
  98. UTIL_SetModel( this, STRING( GetModelName() ) );
  99. if ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
  100. {
  101. if ( dynamic_cast< CRagdollProp* >( GetMoveParent() ) )
  102. {
  103. SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + 0.01f, s_pElectroThinkContext );
  104. }
  105. }
  106. // Setup our times
  107. m_flFadeInStart = DISSOLVE_FADE_IN_START_TIME;
  108. m_flFadeInLength = DISSOLVE_FADE_IN_END_TIME - DISSOLVE_FADE_IN_START_TIME;
  109. m_flFadeOutModelStart = DISSOLVE_FADE_OUT_MODEL_START_TIME;
  110. m_flFadeOutModelLength = DISSOLVE_FADE_OUT_MODEL_END_TIME - DISSOLVE_FADE_OUT_MODEL_START_TIME;
  111. m_flFadeOutStart = DISSOLVE_FADE_OUT_START_TIME;
  112. m_flFadeOutLength = DISSOLVE_FADE_OUT_END_TIME - DISSOLVE_FADE_OUT_START_TIME;
  113. if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
  114. {
  115. m_flFadeInStart = 0.0f;
  116. m_flFadeOutStart = CORE_DISSOLVE_FADE_START;
  117. m_flFadeOutModelStart = CORE_DISSOLVE_MODEL_FADE_START;
  118. m_flFadeOutModelLength = CORE_DISSOLVE_MODEL_FADE_LENGTH;
  119. m_flFadeInLength = CORE_DISSOLVE_FADEIN_LENGTH;
  120. }
  121. m_nRenderMode = kRenderTransColor;
  122. SetRenderColor( 255, 255, 255 );
  123. SetRenderAlpha( 255 );
  124. m_nRenderFX = kRenderFxNone;
  125. SetThink( &CEntityDissolve::DissolveThink );
  126. if ( gpGlobals->curtime > m_flStartTime )
  127. {
  128. // Necessary for server-side ragdolls
  129. DissolveThink();
  130. }
  131. else
  132. {
  133. SetNextThink( gpGlobals->curtime + 0.01f );
  134. }
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. // Input : inputdata -
  139. //-----------------------------------------------------------------------------
  140. void CEntityDissolve::InputDissolve( inputdata_t &inputdata )
  141. {
  142. string_t strTarget = inputdata.value.StringID();
  143. if (strTarget == NULL_STRING)
  144. {
  145. strTarget = m_target;
  146. }
  147. CBaseEntity *pTarget = NULL;
  148. while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(strTarget), this, inputdata.pActivator)) != NULL)
  149. {
  150. CBaseAnimating *pBaseAnim = pTarget->GetBaseAnimating();
  151. if (pBaseAnim)
  152. {
  153. pBaseAnim->Dissolve( NULL, gpGlobals->curtime, false, m_nDissolveType, GetAbsOrigin(), m_nMagnitude );
  154. }
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Creates a flame and attaches it to a target entity.
  159. // Input : pTarget -
  160. //-----------------------------------------------------------------------------
  161. CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName,
  162. float flStartTime, int nDissolveType, bool *pRagdollCreated )
  163. {
  164. if ( pRagdollCreated )
  165. {
  166. *pRagdollCreated = false;
  167. }
  168. if ( !pMaterialName )
  169. {
  170. pMaterialName = DISSOLVE_SPRITE_NAME;
  171. }
  172. if ( pTarget->IsPlayer() )
  173. {
  174. // Simply immediately kill the player.
  175. CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
  176. pPlayer->SetArmorValue( 0 );
  177. CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
  178. pPlayer->TakeDamage( info );
  179. return NULL;
  180. }
  181. CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );
  182. if ( pDissolve == NULL )
  183. return NULL;
  184. pDissolve->m_nDissolveType = nDissolveType;
  185. if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
  186. {
  187. if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
  188. {
  189. CTakeDamageInfo info;
  190. CBaseEntity *pRagdoll = CreateServerRagdoll( pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true );
  191. pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );
  192. // Necessary to cause it to do the appropriate death cleanup
  193. if ( pTarget->m_lifeState == LIFE_ALIVE )
  194. {
  195. CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
  196. CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
  197. pTarget->TakeDamage( ragdollInfo );
  198. }
  199. if ( pRagdollCreated )
  200. {
  201. *pRagdollCreated = true;
  202. }
  203. UTIL_Remove( pTarget );
  204. pTarget = pRagdoll;
  205. }
  206. }
  207. pDissolve->SetModelName( AllocPooledString(pMaterialName) );
  208. pDissolve->AttachToEntity( pTarget );
  209. pDissolve->SetStartTime( flStartTime );
  210. pDissolve->Spawn();
  211. // Send to the client even though we don't have a model
  212. pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  213. // Play any appropriate noises when we start to dissolve
  214. if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
  215. {
  216. pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
  217. }
  218. else
  219. {
  220. pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
  221. }
  222. return pDissolve;
  223. }
  224. //-----------------------------------------------------------------------------
  225. // What type of dissolve?
  226. //-----------------------------------------------------------------------------
  227. CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, CBaseEntity *pSource )
  228. {
  229. // Look for other boogies on the ragdoll + kill them
  230. for ( CBaseEntity *pChild = pSource->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
  231. {
  232. CEntityDissolve *pDissolve = dynamic_cast<CEntityDissolve*>(pChild);
  233. if ( !pDissolve )
  234. continue;
  235. return Create( pTarget, STRING( pDissolve->GetModelName() ), pDissolve->m_flStartTime, pDissolve->m_nDissolveType );
  236. }
  237. return NULL;
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Attaches the flame to an entity and moves with it
  241. // Input : pTarget - target entity to attach to
  242. //-----------------------------------------------------------------------------
  243. void CEntityDissolve::AttachToEntity( CBaseEntity *pTarget )
  244. {
  245. // So our dissolver follows the entity around on the server.
  246. SetParent( pTarget );
  247. SetLocalOrigin( vec3_origin );
  248. SetLocalAngles( vec3_angle );
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. // Input : lifetime -
  253. //-----------------------------------------------------------------------------
  254. void CEntityDissolve::SetStartTime( float flStartTime )
  255. {
  256. m_flStartTime = flStartTime;
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose: Burn targets around us
  260. //-----------------------------------------------------------------------------
  261. void CEntityDissolve::DissolveThink( void )
  262. {
  263. CBaseAnimating *pTarget = ( GetMoveParent() ) ? GetMoveParent()->GetBaseAnimating() : NULL;
  264. if ( GetModelName() == NULL_STRING && pTarget == NULL )
  265. return;
  266. if ( pTarget == NULL )
  267. {
  268. UTIL_Remove( this );
  269. return;
  270. }
  271. // Turn them into debris
  272. pTarget->SetCollisionGroup( COLLISION_GROUP_DISSOLVING );
  273. if ( pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL )
  274. {
  275. SetRenderAlpha( 0 );
  276. }
  277. float dt = gpGlobals->curtime - m_flStartTime;
  278. if ( dt < m_flFadeInStart )
  279. {
  280. SetNextThink( m_flStartTime + m_flFadeInStart );
  281. return;
  282. }
  283. // If we're done fading, then kill our target entity and us
  284. if ( dt >= m_flFadeOutStart + m_flFadeOutLength )
  285. {
  286. // Necessary to cause it to do the appropriate death cleanup
  287. // Yeah, the player may have nothing to do with it, but
  288. // passing NULL to TakeDamage causes bad things to happen
  289. CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
  290. int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
  291. CTakeDamageInfo info( pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage );
  292. pTarget->TakeDamage( info );
  293. if ( pTarget != pPlayer )
  294. {
  295. UTIL_Remove( pTarget );
  296. }
  297. UTIL_Remove( this );
  298. return;
  299. }
  300. SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Purpose: Burn targets around us
  304. //-----------------------------------------------------------------------------
  305. void CEntityDissolve::ElectrocuteThink( void )
  306. {
  307. CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
  308. if ( !pRagdoll )
  309. return;
  310. ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
  311. for ( int j = 0; j < pRagdollPhys->listCount; ++j )
  312. {
  313. Vector vecForce;
  314. vecForce = RandomVector( -2400.0f, 2400.0f );
  315. pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
  316. }
  317. SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ),
  318. s_pElectroThinkContext );
  319. }