aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/gib.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/server/gib.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/server/gib.cpp')
-rw-r--r--mp/src/game/server/gib.cpp679
1 files changed, 679 insertions, 0 deletions
diff --git a/mp/src/game/server/gib.cpp b/mp/src/game/server/gib.cpp
new file mode 100644
index 00000000..4d64fa19
--- /dev/null
+++ b/mp/src/game/server/gib.cpp
@@ -0,0 +1,679 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A gib is a chunk of a body, or a piece of wood/metal/rocks/etc.
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//===========================================================================//
+
+#include "cbase.h"
+#include "gib.h"
+#include "soundent.h"
+#include "func_break.h" // For materials
+#include "player.h"
+#include "vstdlib/random.h"
+#include "ai_utils.h"
+#include "EntityFlame.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern Vector g_vecAttackDir; // In globals.cpp
+
+BEGIN_DATADESC( CGib )
+
+ // gibs are not saved/restored
+// DEFINE_FIELD( m_bloodColor, FIELD_INTEGER ),
+// DEFINE_FIELD( m_hSprite, FIELD_EHANDLE ),
+// DEFINE_FIELD( m_cBloodDecals, FIELD_INTEGER ),
+// DEFINE_FIELD( m_material, FIELD_INTEGER ),
+// DEFINE_FIELD( m_lifeTime, FIELD_TIME ),
+// DEFINE_FIELD( m_pSprite, CSprite ),
+// DEFINE_FIELD( m_hFlame, FIELD_EHANDLE ),
+
+// DEFINE_FIELD( m_hPhysicsAttacker, FIELD_EHANDLE ),
+// DEFINE_FIELD( m_flLastPhysicsInfluenceTime, FIELD_TIME ),
+
+// DEFINE_FIELD( m_bForceRemove, FIELD_BOOLEAN ),
+
+ // Function pointers
+ DEFINE_ENTITYFUNC( BounceGibTouch ),
+ DEFINE_ENTITYFUNC( StickyGibTouch ),
+ DEFINE_THINKFUNC( WaitTillLand ),
+ DEFINE_THINKFUNC( DieThink ),
+
+END_DATADESC()
+
+
+// HACKHACK -- The gib velocity equations don't work
+void CGib::LimitVelocity( void )
+{
+ Vector vecNewVelocity = GetAbsVelocity();
+ float length = VectorNormalize( vecNewVelocity );
+
+ // ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it
+ // in 3 separate places again, I'll just limit it here.
+ if ( length > 1500.0 )
+ {
+ vecNewVelocity *= 1500; // This should really be sv_maxvelocity * 0.75 or something
+ SetAbsVelocity( vecNewVelocity );
+ }
+}
+
+
+void CGib::SpawnStickyGibs( CBaseEntity *pVictim, Vector vecOrigin, int cGibs )
+{
+ int i;
+
+ if ( g_Language.GetInt() == LANGUAGE_GERMAN )
+ {
+ // no sticky gibs in germany right now!
+ return;
+ }
+
+ for ( i = 0 ; i < cGibs ; i++ )
+ {
+ CGib *pGib = (CGib *)CreateEntityByName( "gib" );
+
+ pGib->Spawn( "models/stickygib.mdl" );
+ pGib->m_nBody = random->RandomInt(0,2);
+
+ if ( pVictim )
+ {
+ pGib->SetLocalOrigin(
+ Vector( vecOrigin.x + random->RandomFloat( -3, 3 ),
+ vecOrigin.y + random->RandomFloat( -3, 3 ),
+ vecOrigin.z + random->RandomFloat( -3, 3 ) ) );
+
+ // make the gib fly away from the attack vector
+ Vector vecNewVelocity = g_vecAttackDir * -1;
+
+ // mix in some noise
+ vecNewVelocity.x += random->RandomFloat ( -0.15, 0.15 );
+ vecNewVelocity.y += random->RandomFloat ( -0.15, 0.15 );
+ vecNewVelocity.z += random->RandomFloat ( -0.15, 0.15 );
+
+ vecNewVelocity *= 900;
+
+ QAngle vecAngVelocity( random->RandomFloat ( 250, 400 ), random->RandomFloat ( 250, 400 ), 0 );
+ pGib->SetLocalAngularVelocity( vecAngVelocity );
+
+ // copy owner's blood color
+ pGib->SetBloodColor( pVictim->BloodColor() );
+
+ pGib->AdjustVelocityBasedOnHealth( pVictim->m_iHealth, vecNewVelocity );
+ pGib->SetAbsVelocity( vecNewVelocity );
+
+ pGib->SetMoveType( MOVETYPE_FLYGRAVITY );
+ pGib->RemoveSolidFlags( FSOLID_NOT_SOLID );
+ pGib->SetCollisionBounds( vec3_origin, vec3_origin );
+ pGib->SetTouch ( &CGib::StickyGibTouch );
+ pGib->SetThink (NULL);
+ }
+ pGib->LimitVelocity();
+ }
+}
+
+void CGib::SpawnHeadGib( CBaseEntity *pVictim )
+{
+ CGib *pGib = CREATE_ENTITY( CGib, "gib" );
+
+ if ( g_Language.GetInt() == LANGUAGE_GERMAN )
+ {
+ pGib->Spawn( "models/germangibs.mdl" );// throw one head
+ pGib->m_nBody = 0;
+ }
+ else
+ {
+ pGib->Spawn( "models/gibs/hgibs.mdl" );// throw one head
+ pGib->m_nBody = 0;
+ }
+
+ if ( pVictim )
+ {
+ Vector vecNewVelocity = pGib->GetAbsVelocity();
+
+ pGib->SetLocalOrigin( pVictim->EyePosition() );
+
+ edict_t *pentPlayer = UTIL_FindClientInPVS( pGib->edict() );
+
+ if ( random->RandomInt ( 0, 100 ) <= 5 && pentPlayer )
+ {
+ // 5% chance head will be thrown at player's face.
+ CBasePlayer *player = (CBasePlayer *)CBaseEntity::Instance( pentPlayer );
+ if ( player )
+ {
+ vecNewVelocity = ( player->EyePosition() ) - pGib->GetAbsOrigin();
+ VectorNormalize(vecNewVelocity);
+ vecNewVelocity *= 300;
+ vecNewVelocity.z += 100;
+ }
+ }
+ else
+ {
+ vecNewVelocity = Vector (random->RandomFloat(-100,100), random->RandomFloat(-100,100), random->RandomFloat(200,300));
+ }
+
+ QAngle vecNewAngularVelocity = pGib->GetLocalAngularVelocity();
+ vecNewAngularVelocity.x = random->RandomFloat ( 100, 200 );
+ vecNewAngularVelocity.y = random->RandomFloat ( 100, 300 );
+ pGib->SetLocalAngularVelocity( vecNewAngularVelocity );
+
+ // copy owner's blood color
+ pGib->SetBloodColor( pVictim->BloodColor() );
+ pGib->AdjustVelocityBasedOnHealth( pVictim->m_iHealth, vecNewVelocity );
+ pGib->SetAbsVelocity( vecNewVelocity );
+ }
+ pGib->LimitVelocity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Blood color (see BLOOD_COLOR_* macros in baseentity.h)
+//-----------------------------------------------------------------------------
+void CGib::SetBloodColor( int nBloodColor )
+{
+ m_bloodColor = nBloodColor;
+}
+
+
+//------------------------------------------------------------------------------
+// A little piece of duplicated code
+//------------------------------------------------------------------------------
+void CGib::AdjustVelocityBasedOnHealth( int nHealth, Vector &vecVelocity )
+{
+ if ( nHealth > -50)
+ {
+ vecVelocity *= 0.7;
+ }
+ else if ( nHealth > -200)
+ {
+ vecVelocity *= 2;
+ }
+ else
+ {
+ vecVelocity *= 4;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose : Initialize a gibs position and velocity
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CGib::InitGib( CBaseEntity *pVictim, float fMinVelocity, float fMaxVelocity )
+{
+ // ------------------------------------------------------------------------
+ // If have a pVictim spawn the gib somewhere in the pVictim's bounding volume
+ // ------------------------------------------------------------------------
+ if ( pVictim )
+ {
+ // Find a random position within the bounding box (add 1 to Z to get it out of the ground)
+ Vector vecOrigin;
+ pVictim->CollisionProp()->RandomPointInBounds( vec3_origin, Vector( 1, 1, 1 ), &vecOrigin );
+ vecOrigin.z += 1.0f;
+ SetAbsOrigin( vecOrigin );
+
+ // make the gib fly away from the attack vector
+ Vector vecNewVelocity = g_vecAttackDir * -1;
+
+ // mix in some noise
+ vecNewVelocity.x += random->RandomFloat ( -0.25, 0.25 );
+ vecNewVelocity.y += random->RandomFloat ( -0.25, 0.25 );
+ vecNewVelocity.z += random->RandomFloat ( -0.25, 0.25 );
+
+ vecNewVelocity *= random->RandomFloat ( fMaxVelocity, fMinVelocity );
+
+ QAngle vecNewAngularVelocity = GetLocalAngularVelocity();
+ vecNewAngularVelocity.x = random->RandomFloat ( 100, 200 );
+ vecNewAngularVelocity.y = random->RandomFloat ( 100, 300 );
+ SetLocalAngularVelocity( vecNewAngularVelocity );
+
+ // copy owner's blood color
+ SetBloodColor( pVictim->BloodColor() );
+
+ AdjustVelocityBasedOnHealth( pVictim->m_iHealth, vecNewVelocity );
+
+ // Attempt to be physical if we can
+ if ( VPhysicsInitNormal( SOLID_BBOX, 0, false ) )
+ {
+ IPhysicsObject *pObj = VPhysicsGetObject();
+
+ if ( pObj != NULL )
+ {
+ AngularImpulse angImpulse = RandomAngularImpulse( -500, 500 );
+ pObj->AddVelocity( &vecNewVelocity, &angImpulse );
+ }
+ }
+ else
+ {
+ SetSolid( SOLID_BBOX );
+ SetCollisionBounds( vec3_origin, vec3_origin );
+ SetAbsVelocity( vecNewVelocity );
+ }
+
+ SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+ }
+
+ LimitVelocity();
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Given an .mdl file with gibs and the number of gibs in the file
+// spawns them in pVictim's bounding box
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CGib::SpawnSpecificGibs( CBaseEntity* pVictim,
+ int nNumGibs,
+ float vMinVelocity,
+ float vMaxVelocity,
+ const char* cModelName,
+ float flLifetime)
+{
+ for (int i=0;i<nNumGibs;i++)
+ {
+ CGib *pGib = CREATE_ENTITY( CGib, "gib" );
+ pGib->Spawn( cModelName );
+ pGib->m_nBody = i;
+ pGib->InitGib( pVictim, vMinVelocity, vMaxVelocity );
+ pGib->m_lifeTime = flLifetime;
+
+ if ( pVictim != NULL )
+ {
+ pGib->SetOwnerEntity( pVictim );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Spawn random gibs of the given gib type
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CGib::SpawnRandomGibs( CBaseEntity *pVictim, int cGibs, GibType_e eGibType )
+{
+ int cSplat;
+
+ for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ )
+ {
+ CGib *pGib = CREATE_ENTITY( CGib, "gib" );
+
+ if ( g_Language.GetInt() == LANGUAGE_GERMAN )
+ {
+ pGib->Spawn( "models/germangibs.mdl" );
+ pGib->m_nBody = random->RandomInt(0,GERMAN_GIB_COUNT-1);
+ }
+ else
+ {
+ switch (eGibType)
+ {
+ case GIB_HUMAN:
+ // human pieces
+ pGib->Spawn( "models/gibs/hgibs.mdl" );
+ pGib->m_nBody = random->RandomInt(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib)
+ break;
+ case GIB_ALIEN:
+ // alien pieces
+ pGib->Spawn( "models/gibs/agibs.mdl" );
+ pGib->m_nBody = random->RandomInt(0,ALIEN_GIB_COUNT-1);
+ break;
+ }
+ }
+ pGib->InitGib( pVictim, 300, 400);
+ }
+}
+
+//=========================================================
+// WaitTillLand - in order to emit their meaty scent from
+// the proper location, gibs should wait until they stop
+// bouncing to emit their scent. That's what this function
+// does.
+//=========================================================
+void CGib::WaitTillLand ( void )
+{
+ if (!IsInWorld())
+ {
+ UTIL_Remove( this );
+ return;
+ }
+
+ if ( GetAbsVelocity() == vec3_origin )
+ {
+ SetRenderColorA( 255 );
+ m_nRenderMode = kRenderTransTexture;
+ if ( GetMoveType() != MOVETYPE_VPHYSICS )
+ {
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ }
+ SetLocalAngularVelocity( vec3_angle );
+
+ SetNextThink( gpGlobals->curtime + m_lifeTime );
+ SetThink ( &CGib::SUB_FadeOut );
+
+ if ( GetSprite() )
+ {
+ CSprite *pSprite = dynamic_cast<CSprite*>( GetSprite() );
+
+ if ( pSprite )
+ {
+ //Adrian - Why am I doing this? Check InitPointGib for the answer!
+ if ( m_lifeTime == 0 )
+ m_lifeTime = random->RandomFloat( 1, 3 );
+
+ pSprite->FadeAndDie( m_lifeTime );
+ }
+ }
+
+ if ( GetFlame() )
+ {
+ CEntityFlame *pFlame = dynamic_cast< CEntityFlame*>( GetFlame() );
+
+ if ( pFlame )
+ {
+ pFlame->SetLifetime( 1.0f );
+ }
+ }
+
+ // If you bleed, you stink!
+ if ( m_bloodColor != DONT_BLEED )
+ {
+ // ok, start stinkin!
+ // FIXME: It's too easy to fill up the sound queue with all these meat sounds
+ // CSoundEnt::InsertSound ( SOUND_MEAT, GetAbsOrigin(), 384, 25 );
+ }
+ }
+ else
+ {
+ // wait and check again in another half second.
+ SetNextThink( gpGlobals->curtime + 0.5f );
+ }
+}
+
+bool CGib::SUB_AllowedToFade( void )
+{
+ if( VPhysicsGetObject() )
+ {
+ if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE )
+ return false;
+ }
+
+ CBasePlayer *pPlayer = ( AI_IsSinglePlayer() ) ? UTIL_GetLocalPlayer() : NULL;
+
+ if ( pPlayer && pPlayer->FInViewCone( this ) && m_bForceRemove == false )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+void CGib::DieThink ( void )
+{
+ if ( GetSprite() )
+ {
+ CSprite *pSprite = dynamic_cast<CSprite*>( GetSprite() );
+
+ if ( pSprite )
+ {
+ pSprite->FadeAndDie( 0.0 );
+ }
+ }
+
+ if ( GetFlame() )
+ {
+ CEntityFlame *pFlame = dynamic_cast< CEntityFlame*>( GetFlame() );
+
+ if ( pFlame )
+ {
+ pFlame->SetLifetime( 1.0f );
+ }
+ }
+
+ if ( g_pGameRules->IsMultiplayer() )
+ {
+ UTIL_Remove( this );
+ }
+ else
+ {
+ SetThink ( &CGib::SUB_FadeOut );
+ SetNextThink( gpGlobals->curtime );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGib::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( pActivator );
+
+ if ( pPlayer )
+ {
+ pPlayer->PickupObject( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Physics Attacker
+//-----------------------------------------------------------------------------
+void CGib::SetPhysicsAttacker( CBasePlayer *pEntity, float flTime )
+{
+ m_hPhysicsAttacker = pEntity;
+ m_flLastPhysicsInfluenceTime = flTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Keep track of physgun influence
+//-----------------------------------------------------------------------------
+void CGib::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
+{
+ SetPhysicsAttacker( pPhysGunUser, gpGlobals->curtime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGib::OnPhysGunDrop( CBasePlayer *pPhysGunUser, PhysGunDrop_t Reason )
+{
+ SetPhysicsAttacker( pPhysGunUser, gpGlobals->curtime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CBasePlayer *CGib::HasPhysicsAttacker( float dt )
+{
+ if (gpGlobals->curtime - dt <= m_flLastPhysicsInfluenceTime)
+ {
+ return m_hPhysicsAttacker;
+ }
+ return NULL;
+}
+
+
+//
+// Gib bounces on the ground or wall, sponges some blood down, too!
+//
+void CGib::BounceGibTouch ( CBaseEntity *pOther )
+{
+ Vector vecSpot;
+ trace_t tr;
+
+ IPhysicsObject *pPhysics = VPhysicsGetObject();
+
+ if ( pPhysics )
+ return;
+
+ //if ( random->RandomInt(0,1) )
+ // return;// don't bleed everytime
+ if (GetFlags() & FL_ONGROUND)
+ {
+ SetAbsVelocity( GetAbsVelocity() * 0.9 );
+ QAngle angles = GetLocalAngles();
+ angles.x = 0;
+ angles.z = 0;
+ SetLocalAngles( angles );
+
+ QAngle angVel = GetLocalAngularVelocity();
+ angVel.x = 0;
+ angVel.z = 0;
+ SetLocalAngularVelocity( vec3_angle );
+ }
+ else
+ {
+ if ( g_Language.GetInt() != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED )
+ {
+ vecSpot = GetAbsOrigin() + Vector ( 0 , 0 , 8 );//move up a bit, and trace down.
+ UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
+
+ UTIL_BloodDecalTrace( &tr, m_bloodColor );
+
+ m_cBloodDecals--;
+ }
+
+ if ( m_material != matNone && random->RandomInt(0,2) == 0 )
+ {
+ float volume;
+ float zvel = fabs(GetAbsVelocity().z);
+
+ volume = 0.8f * MIN(1.0, ((float)zvel) / 450.0f);
+
+ CBreakable::MaterialSoundRandom( entindex(), (Materials)m_material, volume );
+ }
+ }
+}
+
+//
+// Sticky gib puts blood on the wall and stays put.
+//
+void CGib::StickyGibTouch ( CBaseEntity *pOther )
+{
+ Vector vecSpot;
+ trace_t tr;
+
+ SetThink ( &CGib::SUB_Remove );
+ SetNextThink( gpGlobals->curtime + 10 );
+
+ if ( !FClassnameIs( pOther, "worldspawn" ) )
+ {
+ SetNextThink( gpGlobals->curtime );
+ return;
+ }
+
+ UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 32, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
+
+ UTIL_BloodDecalTrace( &tr, m_bloodColor );
+
+ Vector vecForward = tr.plane.normal * -1;
+ QAngle angles;
+ VectorAngles( vecForward, angles );
+ SetLocalAngles( angles );
+ SetAbsVelocity( vec3_origin );
+ SetLocalAngularVelocity( vec3_angle );
+ SetMoveType( MOVETYPE_NONE );
+}
+
+//
+// Throw a chunk
+//
+void CGib::Spawn( const char *szGibModel )
+{
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
+ SetFriction(0.55); // deading the bounce a bit
+
+ // sometimes an entity inherits the edict from a former piece of glass,
+ // and will spawn using the same render FX or m_nRenderMode! bad!
+ SetRenderColorA( 255 );
+ m_nRenderMode = kRenderNormal;
+ m_nRenderFX = kRenderFxNone;
+
+ // hopefully this will fix the VELOCITY TOO LOW crap
+ m_takedamage = DAMAGE_EVENTS_ONLY;
+ SetSolid( SOLID_BBOX );
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+ SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+
+ SetModel( szGibModel );
+
+#ifdef HL1_DLL
+ SetElasticity( 1.0 );
+ UTIL_SetSize( this, vec3_origin, vec3_origin );
+#endif//HL1_DLL
+
+ SetNextThink( gpGlobals->curtime + 4 );
+ m_lifeTime = 25;
+ SetTouch ( &CGib::BounceGibTouch );
+
+ m_bForceRemove = false;
+
+ m_material = matNone;
+ m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain).
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Spawn a gib with a finite lifetime, after which it will fade out.
+//-----------------------------------------------------------------------------
+void CGib::Spawn( const char *szGibModel, float flLifetime )
+{
+ Spawn( szGibModel );
+ m_lifeTime = flLifetime;
+ SetThink ( &CGib::SUB_FadeOut );
+ SetNextThink( gpGlobals->curtime + m_lifeTime );
+}
+
+
+LINK_ENTITY_TO_CLASS( gib, CGib );
+
+CBaseEntity *CreateRagGib( const char *szModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecForce, float flFadeTime, bool bShouldIgnite )
+{
+ CRagGib *pGib;
+
+ pGib = (CRagGib*)CreateEntityByName( "raggib" );
+
+ pGib->SetLocalAngles( vecAngles );
+
+ if ( !pGib )
+ {
+ Msg( "**Can't create ragdoll gib!\n" );
+ return NULL;
+ }
+
+ if ( bShouldIgnite )
+ {
+ CBaseAnimating *pAnimating = pGib->GetBaseAnimating();
+ if (pAnimating != NULL )
+ {
+ pAnimating->Ignite( random->RandomFloat( 8.0, 12.0 ), false );
+ }
+ }
+
+ pGib->Spawn( szModel, vecOrigin, vecForce, flFadeTime );
+
+ return pGib;
+}
+
+void CRagGib::Spawn( const char *szModel, const Vector &vecOrigin, const Vector &vecForce, float flFadeTime = 0.0 )
+{
+ SetSolid( SOLID_BBOX );
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ SetModel( szModel );
+ UTIL_SetSize(this, vec3_origin, vec3_origin);
+ UTIL_SetOrigin( this, vecOrigin );
+ if ( !BecomeRagdollOnClient( vecForce ) )
+ {
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+ if( flFadeTime > 0.0 )
+ {
+ SUB_StartFadeOut( flFadeTime );
+ }
+ }
+}
+
+LINK_ENTITY_TO_CLASS( raggib, CRagGib );