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.

873 lines
21 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "physpropclientside.h"
  8. #include "vcollide_parse.h"
  9. #include "mapentities_shared.h"
  10. #include "gamestringpool.h"
  11. #include "props_shared.h"
  12. #include "c_te_effect_dispatch.h"
  13. #include "datacache/imdlcache.h"
  14. #include "view.h"
  15. #include "tier0/vprof.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #define FADEOUT_TIME 1.0f
  19. ConVar r_propsmaxdist( "r_propsmaxdist", "1200", 0, "Maximum visible distance" );
  20. //////////////////////////////////////////////////////////////////////
  21. // Construction/Destruction
  22. //////////////////////////////////////////////////////////////////////
  23. static int PropBreakablePrecacheAll( int modelIndex )
  24. {
  25. CUtlVector<breakmodel_t> list;
  26. BreakModelList( list, modelIndex, COLLISION_GROUP_NONE, 0 );
  27. return list.Count();
  28. }
  29. C_PhysPropClientside *C_PhysPropClientside::CreateNew( bool bForce )
  30. {
  31. return new C_PhysPropClientside();
  32. }
  33. C_PhysPropClientside::C_PhysPropClientside()
  34. {
  35. m_fDeathTime = -1;
  36. m_impactEnergyScale = 1.0f;
  37. m_iHealth = 0;
  38. m_iPhysicsMode = PHYSICS_MULTIPLAYER_AUTODETECT;
  39. m_flTouchDelta = 0;
  40. }
  41. C_PhysPropClientside::~C_PhysPropClientside()
  42. {
  43. PhysCleanupFrictionSounds( this );
  44. VPhysicsDestroyObject();
  45. }
  46. void C_PhysPropClientside::SetPhysicsMode(int iMode)
  47. {
  48. if ( m_iPhysicsMode == PHYSICS_MULTIPLAYER_AUTODETECT )
  49. m_iPhysicsMode = iMode;
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Should we collide?
  53. //-----------------------------------------------------------------------------
  54. bool C_PhysPropClientside::KeyValue( const char *szKeyName, const char *szValue )
  55. {
  56. if (FStrEq(szKeyName, "physdamagescale"))
  57. {
  58. m_impactEnergyScale = atof(szValue);
  59. }
  60. else if ( FStrEq(szKeyName, "health") )
  61. {
  62. m_iHealth = Q_atoi(szValue);
  63. }
  64. else if (FStrEq(szKeyName, "spawnflags"))
  65. {
  66. m_spawnflags = Q_atoi(szValue);
  67. }
  68. else if (FStrEq(szKeyName, "model"))
  69. {
  70. SetModelName( AllocPooledString( szValue ) );
  71. }
  72. else if (FStrEq(szKeyName, "fademaxdist"))
  73. {
  74. float flFadeMaxDist = Q_atof(szValue);
  75. SetDistanceFade( GetMinFadeDist(), flFadeMaxDist );
  76. }
  77. else if (FStrEq(szKeyName, "fademindist"))
  78. {
  79. float flFadeMinDist = Q_atof(szValue);
  80. SetDistanceFade( flFadeMinDist, GetMaxFadeDist() );
  81. }
  82. else if (FStrEq(szKeyName, "fadescale"))
  83. {
  84. SetGlobalFadeScale( Q_atof(szValue) );
  85. }
  86. else if (FStrEq(szKeyName, "inertiaScale"))
  87. {
  88. m_inertiaScale = Q_atof(szValue);
  89. }
  90. else if (FStrEq(szKeyName, "skin"))
  91. {
  92. SetSkin( Q_atoi(szValue) );
  93. }
  94. else if (FStrEq(szKeyName, "physicsmode"))
  95. {
  96. m_iPhysicsMode = Q_atoi(szValue);
  97. }
  98. else
  99. {
  100. if ( !BaseClass::KeyValue( szKeyName, szValue ) )
  101. {
  102. // key hasn't been handled
  103. return false;
  104. }
  105. }
  106. return true;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. // Input : *pOther -
  111. //-----------------------------------------------------------------------------
  112. void C_PhysPropClientside::StartTouch( C_BaseEntity *pOther )
  113. {
  114. // Limit the amount of times we can bounce
  115. if ( m_flTouchDelta < gpGlobals->curtime )
  116. {
  117. HitSurface( pOther );
  118. m_flTouchDelta = gpGlobals->curtime + 0.1f;
  119. }
  120. BaseClass::StartTouch( pOther );
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose:
  124. // Input : *pOther -
  125. //-----------------------------------------------------------------------------
  126. void C_PhysPropClientside::HitSurface( C_BaseEntity *pOther )
  127. {
  128. if ( HasInteraction( PROPINTER_WORLD_BLOODSPLAT ) )
  129. {
  130. trace_t tr;
  131. tr = BaseClass::GetTouchTrace();
  132. if ( tr.m_pEnt )
  133. {
  134. UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
  135. }
  136. }
  137. }
  138. void C_PhysPropClientside::RecreateAll()
  139. {
  140. DestroyAll();
  141. ParseAllEntities( engine->GetMapEntitiesString() );
  142. }
  143. void C_PhysPropClientside::DestroyAll()
  144. {
  145. C_BaseEntityIterator iterator;
  146. C_BaseEntity *pEnt;
  147. while ( (pEnt = iterator.Next()) != NULL )
  148. {
  149. C_PhysPropClientside *pProp = dynamic_cast<C_PhysPropClientside *>(pEnt);
  150. if ( pProp )
  151. {
  152. pProp->Release();
  153. }
  154. }
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: Parse this prop's data from the model, if it has a keyvalues section.
  158. // Returns true only if this prop is using a model that has a prop_data section that's invalid.
  159. //-----------------------------------------------------------------------------
  160. int C_PhysPropClientside::ParsePropData( void )
  161. {
  162. KeyValues *pModelKV = modelinfo->GetModelKeyValues( GetModel() );
  163. if ( !pModelKV )
  164. return PARSE_FAILED_NO_DATA;
  165. // Do we have a props section?
  166. KeyValues *pkvPropData = pModelKV->FindKey("prop_data");
  167. if ( !pkvPropData )
  168. return PARSE_FAILED_NO_DATA;
  169. int iResult = g_PropDataSystem.ParsePropFromKV( this, this, pkvPropData, pModelKV );
  170. return iResult;
  171. }
  172. bool C_PhysPropClientside::Initialize()
  173. {
  174. if ( InitializeAsClientEntity( STRING(GetModelName()), false ) == false )
  175. {
  176. return false;
  177. }
  178. const model_t *mod = GetModel();
  179. if ( mod )
  180. {
  181. Vector mins, maxs;
  182. modelinfo->GetModelBounds( mod, mins, maxs );
  183. SetCollisionBounds( mins, maxs );
  184. }
  185. solid_t tmpSolid;
  186. // Create the object in the physics system
  187. if ( !PhysModelParseSolid( tmpSolid, this, GetModelIndex() ) )
  188. {
  189. DevMsg("C_PhysPropClientside::Initialize: PhysModelParseSolid failed for entity %i.\n", GetModelIndex() );
  190. return false;
  191. }
  192. else
  193. {
  194. m_pPhysicsObject = VPhysicsInitNormal( SOLID_VPHYSICS, 0, m_spawnflags & SF_PHYSPROP_START_ASLEEP, &tmpSolid );
  195. if ( !m_pPhysicsObject )
  196. {
  197. // failed to create a physics object
  198. DevMsg(" C_PhysPropClientside::Initialize: VPhysicsInitNormal() failed for %s.\n", STRING(GetModelName()) );
  199. return false;
  200. }
  201. }
  202. // We want touch calls when we hit the world
  203. unsigned int flags = VPhysicsGetObject()->GetCallbackFlags();
  204. VPhysicsGetObject()->SetCallbackFlags( flags | CALLBACK_GLOBAL_TOUCH_STATIC );
  205. if ( m_spawnflags & SF_PHYSPROP_MOTIONDISABLED )
  206. {
  207. m_pPhysicsObject->EnableMotion( false );
  208. }
  209. Spawn(); // loads breakable & prop data
  210. if ( m_iPhysicsMode == PHYSICS_MULTIPLAYER_AUTODETECT )
  211. {
  212. m_iPhysicsMode = GetAutoMultiplayerPhysicsMode(
  213. CollisionProp()->OBBSize(), m_pPhysicsObject->GetMass() );
  214. }
  215. if ( m_spawnflags & SF_PHYSPROP_FORCE_SERVER_SIDE )
  216. {
  217. // forced to be server-side by map maker
  218. return false;
  219. }
  220. if ( m_iPhysicsMode != PHYSICS_MULTIPLAYER_CLIENTSIDE )
  221. {
  222. // spawn only clientside entities
  223. return false;
  224. }
  225. else
  226. {
  227. if ( engine->IsInEditMode() )
  228. {
  229. // don't spawn in map edit mode
  230. return false;
  231. }
  232. }
  233. if ( GetMinFadeDist() < 0.0f )
  234. {
  235. // start fading out at 75% of r_propsmaxdist
  236. float flPropsMaxDist = r_propsmaxdist.GetFloat();
  237. SetDistanceFade( flPropsMaxDist * 0.75f, flPropsMaxDist );
  238. }
  239. // player can push it away
  240. SetCollisionGroup( COLLISION_GROUP_PUSHAWAY );
  241. UpdatePartitionListEntry();
  242. CollisionProp()->UpdatePartition();
  243. SetBlocksLOS( false ); // this should be a small object
  244. // Set up shadows; do it here so that objects can change shadowcasting state
  245. CreateShadow();
  246. UpdateVisibility();
  247. SetNextClientThink( CLIENT_THINK_NEVER );
  248. return true;
  249. }
  250. void C_PhysPropClientside::Spawn()
  251. {
  252. // Initialize damage modifiers. Must be done before baseclass spawn.
  253. m_flDmgModBullet = 1.0;
  254. m_flDmgModClub = 1.0;
  255. m_flDmgModExplosive = 1.0;
  256. m_flDmgModFire = 1.0;
  257. BaseClass::Spawn();
  258. // we don't really precache models here, just checking how many we have:
  259. m_iNumBreakableChunks = PropBreakablePrecacheAll( GetModelIndex() );
  260. ParsePropData();
  261. // If we have no custom breakable chunks, see if we're breaking into generic ones
  262. if ( !m_iNumBreakableChunks )
  263. {
  264. if ( GetBreakableModel() != NULL_STRING && GetBreakableCount() )
  265. {
  266. m_iNumBreakableChunks = GetBreakableCount();
  267. }
  268. }
  269. // Setup takedamage based upon the health we parsed earlier
  270. if ( m_iHealth == 0 )
  271. {
  272. m_takedamage = DAMAGE_NO;
  273. }
  274. else
  275. {
  276. m_takedamage = DAMAGE_YES;
  277. }
  278. }
  279. void C_PhysPropClientside::OnTakeDamage( int iDamage ) // very simple version
  280. {
  281. if ( m_takedamage == DAMAGE_NO )
  282. return;
  283. m_iHealth -= iDamage;
  284. if (m_iHealth <= 0)
  285. {
  286. Break();
  287. }
  288. }
  289. float C_PhysPropClientside::GetMass()
  290. {
  291. if ( VPhysicsGetObject() )
  292. {
  293. return VPhysicsGetObject()->GetMass();
  294. }
  295. return 0.0f;
  296. }
  297. bool C_PhysPropClientside::IsAsleep()
  298. {
  299. if ( VPhysicsGetObject() )
  300. {
  301. return VPhysicsGetObject()->IsAsleep();
  302. }
  303. return true;
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose:
  307. //-----------------------------------------------------------------------------
  308. void C_PhysPropClientside::ClientThink( void )
  309. {
  310. if ( m_fDeathTime < 0 )
  311. {
  312. SetNextClientThink( CLIENT_THINK_NEVER );
  313. return;
  314. }
  315. if ( m_fDeathTime <= gpGlobals->curtime )
  316. {
  317. Release(); // Die
  318. return;
  319. }
  320. // fade out
  321. float alpha = (m_fDeathTime - gpGlobals->curtime)/FADEOUT_TIME;
  322. SetRenderMode( kRenderTransTexture );
  323. SetRenderAlpha( alpha * 256 );
  324. SetNextClientThink( CLIENT_THINK_ALWAYS );
  325. }
  326. void C_PhysPropClientside::StartFadeOut( float fDelay )
  327. {
  328. m_fDeathTime = gpGlobals->curtime + fDelay + FADEOUT_TIME;
  329. SetNextClientThink( gpGlobals->curtime + fDelay );
  330. }
  331. void C_PhysPropClientside::Break()
  332. {
  333. m_takedamage = DAMAGE_NO;
  334. IPhysicsObject *pPhysics = VPhysicsGetObject();
  335. Vector velocity;
  336. AngularImpulse angVelocity;
  337. Vector origin;
  338. QAngle angles;
  339. AddSolidFlags( FSOLID_NOT_SOLID );
  340. if ( pPhysics )
  341. {
  342. pPhysics->GetVelocity( &velocity, &angVelocity );
  343. pPhysics->GetPosition( &origin, &angles );
  344. pPhysics->RecheckCollisionFilter();
  345. }
  346. else
  347. {
  348. velocity = GetAbsVelocity();
  349. QAngleToAngularImpulse( GetLocalAngularVelocity(), angVelocity );
  350. origin = GetAbsOrigin();
  351. angles = GetAbsAngles();
  352. }
  353. breakablepropparams_t params( origin, angles, velocity, angVelocity );
  354. params.impactEnergyScale = m_impactEnergyScale;
  355. params.defCollisionGroup = GetCollisionGroup();
  356. if ( params.defCollisionGroup == COLLISION_GROUP_NONE )
  357. {
  358. // don't automatically make anything COLLISION_GROUP_NONE or it will
  359. // collide with debris being ejected by breaking
  360. params.defCollisionGroup = COLLISION_GROUP_INTERACTIVE;
  361. }
  362. // no damage/damage force? set a burst of 100 for some movement
  363. params.defBurstScale = 100;
  364. // spwan break chunks
  365. PropBreakableCreateAll( GetModelIndex(), pPhysics, params, this, -1, false );
  366. STEAMWORKS_TESTSECRET_AMORTIZE(101);
  367. Release(); // destroy object
  368. }
  369. void C_PhysPropClientside::Clone( Vector &velocity )
  370. {
  371. C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew();
  372. if ( !pEntity )
  373. return;
  374. pEntity->m_spawnflags = m_spawnflags;
  375. // We never want to be motion disabled
  376. pEntity->m_spawnflags &= ~SF_PHYSPROP_MOTIONDISABLED;
  377. pEntity->SetDmgModBullet( GetDmgModBullet() );
  378. pEntity->SetDmgModClub( GetDmgModClub() );
  379. pEntity->SetDmgModExplosive( GetDmgModExplosive() );
  380. pEntity->SetModelName( GetModelName() );
  381. pEntity->SetLocalOrigin( GetLocalOrigin() );
  382. pEntity->SetLocalAngles( GetLocalAngles() );
  383. pEntity->SetOwnerEntity( this );
  384. pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE );
  385. if ( !pEntity->Initialize() )
  386. {
  387. pEntity->Release();
  388. return;
  389. }
  390. pEntity->SetSkin( GetSkin() );
  391. pEntity->m_iHealth = m_iHealth;
  392. if ( pEntity->m_iHealth == 0 )
  393. {
  394. // if no health, don't collide with player anymore, don't take damage
  395. pEntity->m_takedamage = DAMAGE_NO;
  396. pEntity->SetCollisionGroup( COLLISION_GROUP_NONE );
  397. }
  398. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  399. if( pPhysicsObject )
  400. {
  401. // randomize velocity by 5%
  402. float rndf = RandomFloat( -0.025, 0.025 );
  403. Vector rndVel = velocity + rndf*velocity;
  404. pPhysicsObject->AddVelocity( &rndVel, NULL );
  405. }
  406. else
  407. {
  408. // failed to create a physics object
  409. pEntity->Release();
  410. }
  411. }
  412. void C_PhysPropClientside::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName )
  413. {
  414. VPROF( "C_PhysPropClientside::ImpactTrace" );
  415. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  416. if( !pPhysicsObject )
  417. return;
  418. Vector dir = pTrace->endpos - pTrace->startpos;
  419. int iDamage = 0;
  420. if ( iDamageType & DMG_BLAST )
  421. {
  422. iDamage = VectorLength( dir );
  423. dir *= 500; // adjust impact strenght
  424. // apply force at object mass center
  425. pPhysicsObject->ApplyForceCenter( dir );
  426. }
  427. else
  428. {
  429. Vector hitpos;
  430. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  431. VectorNormalize( dir );
  432. // guess avg damage
  433. if ( iDamageType == DMG_BULLET )
  434. {
  435. iDamage = 30;
  436. }
  437. else
  438. {
  439. iDamage = 50;
  440. }
  441. dir *= 4000; // adjust impact strenght
  442. // apply force where we hit it
  443. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  444. // Build the impact data
  445. CEffectData data;
  446. data.m_vOrigin = pTrace->endpos;
  447. data.m_vStart = pTrace->startpos;
  448. data.m_nSurfaceProp = pTrace->surface.surfaceProps;
  449. data.m_nDamageType = iDamageType;
  450. data.m_nHitBox = pTrace->hitbox;
  451. data.m_hEntity = GetRefEHandle();
  452. // Send it on its way
  453. if ( !pCustomImpactName )
  454. {
  455. DispatchEffect( "Impact", data );
  456. }
  457. else
  458. {
  459. DispatchEffect( pCustomImpactName, data );
  460. }
  461. }
  462. // Clone( dir ); // debug code
  463. OnTakeDamage( iDamage );
  464. }
  465. const char *C_PhysPropClientside::ParseEntity( const char *pEntData )
  466. {
  467. CEntityMapData entData( (char*)pEntData );
  468. char className[MAPKEY_MAXLENGTH];
  469. MDLCACHE_CRITICAL_SECTION();
  470. if (!entData.ExtractValue("classname", className))
  471. {
  472. Error( "classname missing from entity!\n" );
  473. }
  474. if ( !Q_strcmp( className, "prop_physics_multiplayer" ) )
  475. {
  476. // always force clientside entitis placed in maps
  477. C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew( true );
  478. if ( pEntity )
  479. { // Set up keyvalues.
  480. pEntity->ParseMapData(&entData);
  481. if ( !pEntity->Initialize() )
  482. pEntity->Release();
  483. return entData.CurrentBufferPosition();
  484. }
  485. }
  486. if ( !Q_strcmp( className, "func_proprrespawnzone" ) )
  487. {
  488. DebuggerBreakIfDebugging();
  489. }
  490. // Just skip past all the keys.
  491. char keyName[MAPKEY_MAXLENGTH];
  492. char value[MAPKEY_MAXLENGTH];
  493. if ( entData.GetFirstKey(keyName, value) )
  494. {
  495. do
  496. {
  497. }
  498. while ( entData.GetNextKey(keyName, value) );
  499. }
  500. //
  501. // Return the current parser position in the data block
  502. //
  503. return entData.CurrentBufferPosition();
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Purpose: Only called on BSP load. Parses and spawns all the entities in the BSP.
  507. // Input : pMapData - Pointer to the entity data block to parse.
  508. //-----------------------------------------------------------------------------
  509. void C_PhysPropClientside::ParseAllEntities(const char *pMapData)
  510. {
  511. int nEntities = 0;
  512. char szTokenBuffer[MAPKEY_MAXLENGTH];
  513. //
  514. // Loop through all entities in the map data, creating each.
  515. //
  516. for ( ; true; pMapData = MapEntity_SkipToNextEntity(pMapData, szTokenBuffer) )
  517. {
  518. //
  519. // Parse the opening brace.
  520. //
  521. char token[MAPKEY_MAXLENGTH];
  522. pMapData = MapEntity_ParseToken( pMapData, token );
  523. //
  524. // Check to see if we've finished or not.
  525. //
  526. if (!pMapData)
  527. break;
  528. if (token[0] != '{')
  529. {
  530. Error( "MapEntity_ParseAllEntities: found %s when expecting {", token);
  531. continue;
  532. }
  533. //
  534. // Parse the entity and add it to the spawn list.
  535. //
  536. pMapData = ParseEntity( pMapData );
  537. nEntities++;
  538. }
  539. }
  540. CBaseAnimating *BreakModelCreate_Ragdoll( CBaseEntity *pOwnerEnt, breakmodel_t *pModel, const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity )
  541. {
  542. C_BaseAnimating *pOwner = dynamic_cast<C_BaseAnimating *>( pOwnerEnt );
  543. if ( !pOwner )
  544. return NULL;
  545. C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false );
  546. if ( pRagdoll == NULL )
  547. return NULL;
  548. const char *pModelName = pModel->modelName;
  549. if ( pRagdoll->InitializeAsClientEntity( pModelName, false ) == false )
  550. {
  551. pRagdoll->Release();
  552. return NULL;
  553. }
  554. pRagdoll->SetAbsOrigin( position );
  555. pRagdoll->SetAbsAngles( angles );
  556. matrix3x4a_t boneDelta0[MAXSTUDIOBONES];
  557. matrix3x4a_t boneDelta1[MAXSTUDIOBONES];
  558. matrix3x4a_t currentBones[MAXSTUDIOBONES];
  559. const float boneDt = 0.1f;
  560. pRagdoll->SetParent( pOwner );
  561. pRagdoll->ForceSetupBonesAtTime( boneDelta0, gpGlobals->curtime - boneDt );
  562. pRagdoll->ForceSetupBonesAtTime( boneDelta1, gpGlobals->curtime );
  563. pRagdoll->ForceSetupBonesAtTime( currentBones, gpGlobals->curtime );
  564. pRagdoll->SetParent( NULL );
  565. // We need to take these from the entity
  566. //pRagdoll->SetAbsOrigin( position );
  567. //pRagdoll->SetAbsAngles( angles );
  568. pRagdoll->IgniteRagdoll( pOwner );
  569. pRagdoll->TransferDissolveFrom( pOwner );
  570. pRagdoll->InitModelEffects();
  571. if ( pOwner->IsEffectActive( EF_NOSHADOW ) )
  572. {
  573. pRagdoll->AddEffects( EF_NOSHADOW );
  574. }
  575. pRagdoll->m_bClientSideRagdoll = true;
  576. pRagdoll->SetRenderMode( pOwner->GetRenderMode() );
  577. pRagdoll->SetRenderColor( pOwner->GetRenderColor().r, pOwner->GetRenderColor().g, pOwner->GetRenderColor().b );
  578. pRagdoll->SetRenderAlpha( pOwner->GetRenderAlpha() );
  579. pRagdoll->SetGlobalFadeScale( pOwner->GetGlobalFadeScale() );
  580. pRagdoll->SetSkin( pOwner->GetSkin() );
  581. //pRagdoll->m_vecForce = pOwner->m_vecForce;
  582. //pRagdoll->m_nForceBone = 0; //pOwner->m_nForceBone;
  583. pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS );
  584. pRagdoll->SetModelName( AllocPooledString( pModelName ) );
  585. pRagdoll->ResetSequence( 0 );
  586. pRagdoll->SetModelScale( pOwner->GetModelScale(), pOwner->GetModelScaleType() );
  587. pRagdoll->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  588. //pRagdoll->m_builtRagdoll = true;
  589. CStudioHdr *hdr = pRagdoll->GetModelPtr();
  590. if ( !hdr )
  591. {
  592. pRagdoll->Release();
  593. return NULL;
  594. }
  595. pRagdoll->m_pRagdoll = CreateRagdoll(
  596. pRagdoll,
  597. hdr,
  598. vec3_origin,
  599. 0,
  600. boneDelta0,
  601. boneDelta1,
  602. currentBones,
  603. boneDt );
  604. IPhysicsObject *pPhysicsObject = pRagdoll->VPhysicsGetObject();
  605. if ( pPhysicsObject )
  606. {
  607. // randomize velocity by 5%
  608. float rndf = RandomFloat( -0.025, 0.025 );
  609. Vector rndVel = velocity + rndf*velocity;
  610. pPhysicsObject->AddVelocity( &rndVel, &angVelocity );
  611. }
  612. pRagdoll->ApplyLocalAngularVelocityImpulse( angVelocity );
  613. if ( pRagdoll->m_pRagdoll )
  614. {
  615. pRagdoll->m_bImportant = false;
  616. s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdoll->m_bImportant, pModel->fadeTime > 0.0f ? gpGlobals->curtime + pModel->fadeTime : 0.0f );
  617. pRagdoll->m_bFadeOut = true;
  618. }
  619. // Cause the entity to recompute its shadow type and make a
  620. // version which only updates when physics state changes
  621. // NOTE: We have to do this after m_pRagdoll is assigned above
  622. // because that's what ShadowCastType uses to figure out which type of shadow to use.
  623. pRagdoll->DestroyShadow();
  624. pRagdoll->CreateShadow();
  625. pRagdoll->SetAbsOrigin( position );
  626. pRagdoll->SetAbsAngles( angles );
  627. pRagdoll->SetPlaybackRate( 0 );
  628. pRagdoll->UpdatePartitionListEntry();
  629. pRagdoll->MarkRenderHandleDirty();
  630. //pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
  631. return pRagdoll;
  632. }
  633. CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel, const Vector &position,
  634. const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, int nSkin, const breakablepropparams_t &params )
  635. {
  636. if ( pModel->isRagdoll )
  637. {
  638. CBaseEntity *pEntity = BreakModelCreate_Ragdoll( pOwner, pModel, position, angles, velocity, angVelocity );
  639. return pEntity;
  640. }
  641. C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew();
  642. if ( !pEntity )
  643. return NULL;
  644. // UNDONE: Allow .qc to override spawnflags for child pieces
  645. C_PhysPropClientside *pBreakableOwner = dynamic_cast<C_PhysPropClientside *>(pOwner);
  646. // Inherit the base object's damage modifiers
  647. if ( pBreakableOwner )
  648. {
  649. pEntity->SetEffects( pBreakableOwner->GetEffects() );
  650. pEntity->m_spawnflags = pBreakableOwner->m_spawnflags;
  651. // We never want to be motion disabled
  652. pEntity->m_spawnflags &= ~SF_PHYSPROP_MOTIONDISABLED;
  653. pEntity->SetDmgModBullet( pBreakableOwner->GetDmgModBullet() );
  654. pEntity->SetDmgModClub( pBreakableOwner->GetDmgModClub() );
  655. pEntity->SetDmgModExplosive( pBreakableOwner->GetDmgModExplosive() );
  656. // FIXME: If this was created from a client-side entity which was in the
  657. // middle of ramping the fade scale, we're screwed.
  658. pEntity->CopyFadeFrom( pBreakableOwner );
  659. }
  660. pEntity->SetModelName( AllocPooledString( pModel->modelName ) );
  661. pEntity->SetLocalOrigin( position );
  662. pEntity->SetLocalAngles( angles );
  663. pEntity->SetOwnerEntity( pOwner );
  664. pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE );
  665. if ( !pEntity->Initialize() )
  666. {
  667. pEntity->Release();
  668. return NULL;
  669. }
  670. pEntity->SetSkin( nSkin );
  671. pEntity->m_iHealth = pModel->health;
  672. pEntity->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  673. if ( pModel->health == 0 )
  674. {
  675. // if no health, don't collide with player anymore, don't take damage
  676. pEntity->m_takedamage = DAMAGE_NO;
  677. if ( pEntity->GetCollisionGroup() == COLLISION_GROUP_PUSHAWAY )
  678. {
  679. pEntity->SetCollisionGroup( COLLISION_GROUP_NONE );
  680. }
  681. }
  682. if ( pModel->fadeTime > 0 )
  683. {
  684. pEntity->StartFadeOut( pModel->fadeTime );
  685. }
  686. if ( pModel->fadeMinDist > 0 && pModel->fadeMaxDist >= pModel->fadeMinDist )
  687. {
  688. pEntity->SetDistanceFade( pModel->fadeMinDist, pModel->fadeMaxDist );
  689. }
  690. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  691. if( pPhysicsObject )
  692. {
  693. // randomize velocity by 5%
  694. float rndf = RandomFloat( -0.025, 0.025 );
  695. Vector rndVel = velocity + rndf*velocity;
  696. pPhysicsObject->AddVelocity( &rndVel, &angVelocity );
  697. }
  698. else
  699. {
  700. // failed to create a physics object
  701. pEntity->Release();
  702. return NULL;
  703. }
  704. return pEntity;
  705. }