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.
176 lines
4.6 KiB
176 lines
4.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Implements the Sticky Bolt code. This constraints ragdolls to the world |
|
// after being hit by a crossbow bolt. If something here is acting funny |
|
// let me know - Adrian. |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// |
|
//----------------------------------------------------------------------------- |
|
// $Log: $ |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "c_basetempentity.h" |
|
#include "fx.h" |
|
#include "decals.h" |
|
#include "iefx.h" |
|
#include "engine/IEngineSound.h" |
|
#include "materialsystem/imaterialvar.h" |
|
#include "IEffects.h" |
|
#include "engine/IEngineTrace.h" |
|
#include "vphysics/constraints.h" |
|
#include "engine/ivmodelinfo.h" |
|
#include "tempent.h" |
|
#include "c_te_legacytempents.h" |
|
#include "engine/ivdebugoverlay.h" |
|
#include "c_te_effect_dispatch.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
extern IPhysicsSurfaceProps *physprops; |
|
IPhysicsObject *GetWorldPhysObject( void ); |
|
|
|
extern ITempEnts* tempents; |
|
|
|
class CRagdollBoltEnumerator : public IPartitionEnumerator |
|
{ |
|
public: |
|
//Forced constructor |
|
CRagdollBoltEnumerator( Ray_t& shot, Vector vOrigin ) |
|
{ |
|
m_rayShot = shot; |
|
m_vWorld = vOrigin; |
|
} |
|
|
|
//Actual work code |
|
IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) |
|
{ |
|
C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); |
|
if ( pEnt == NULL ) |
|
return ITERATION_CONTINUE; |
|
|
|
C_BaseAnimating *pModel = static_cast< C_BaseAnimating * >( pEnt ); |
|
|
|
if ( pModel == NULL ) |
|
return ITERATION_CONTINUE; |
|
|
|
trace_t tr; |
|
enginetrace->ClipRayToEntity( m_rayShot, MASK_SHOT, pModel, &tr ); |
|
|
|
IPhysicsObject *pPhysicsObject = NULL; |
|
|
|
//Find the real object we hit. |
|
if( tr.physicsbone >= 0 ) |
|
{ |
|
if ( pModel->m_pRagdoll ) |
|
{ |
|
CRagdoll *pCRagdoll = dynamic_cast < CRagdoll * > ( pModel->m_pRagdoll ); |
|
|
|
if ( pCRagdoll ) |
|
{ |
|
ragdoll_t *pRagdollT = pCRagdoll->GetRagdoll(); |
|
|
|
if ( tr.physicsbone < pRagdollT->listCount ) |
|
{ |
|
pPhysicsObject = pRagdollT->list[tr.physicsbone].pObject; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( pPhysicsObject == NULL ) |
|
return ITERATION_CONTINUE; |
|
|
|
if ( tr.fraction < 1.0 ) |
|
{ |
|
IPhysicsObject *pReference = GetWorldPhysObject(); |
|
|
|
if ( pReference == NULL || pPhysicsObject == NULL ) |
|
return ITERATION_CONTINUE; |
|
|
|
float flMass = pPhysicsObject->GetMass(); |
|
pPhysicsObject->SetMass( flMass * 2 ); |
|
|
|
constraint_ballsocketparams_t ballsocket; |
|
ballsocket.Defaults(); |
|
|
|
pReference->WorldToLocal( &ballsocket.constraintPosition[0], m_vWorld ); |
|
pPhysicsObject->WorldToLocal( &ballsocket.constraintPosition[1], tr.endpos ); |
|
|
|
physenv->CreateBallsocketConstraint( pReference, pPhysicsObject, NULL, ballsocket ); |
|
|
|
//Play a sound |
|
CPASAttenuationFilter filter( pEnt ); |
|
|
|
EmitSound_t ep; |
|
ep.m_nChannel = CHAN_VOICE; |
|
ep.m_pSoundName = "Weapon_Crossbow.BoltSkewer"; |
|
ep.m_flVolume = 1.0f; |
|
ep.m_SoundLevel = SNDLVL_NORM; |
|
ep.m_pOrigin = &pEnt->GetAbsOrigin(); |
|
|
|
C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep ); |
|
|
|
return ITERATION_STOP; |
|
} |
|
|
|
return ITERATION_CONTINUE; |
|
} |
|
|
|
private: |
|
Ray_t m_rayShot; |
|
Vector m_vWorld; |
|
}; |
|
|
|
void CreateCrossbowBolt( const Vector &vecOrigin, const Vector &vecDirection ) |
|
{ |
|
model_t *pModel = (model_t *)engine->LoadModel( "models/crossbow_bolt.mdl" ); |
|
|
|
QAngle vAngles; |
|
|
|
VectorAngles( vecDirection, vAngles ); |
|
|
|
if ( gpGlobals->maxClients > 1 ) |
|
{ |
|
tempents->SpawnTempModel( pModel, vecOrigin - vecDirection * 8, vAngles, Vector(0, 0, 0 ), 30.0f, FTENT_NONE ); |
|
} |
|
else |
|
{ |
|
tempents->SpawnTempModel( pModel, vecOrigin - vecDirection * 8, vAngles, Vector(0, 0, 0 ), 1, FTENT_NEVERDIE ); |
|
} |
|
} |
|
|
|
void StickRagdollNow( const Vector &vecOrigin, const Vector &vecDirection ) |
|
{ |
|
Ray_t shotRay; |
|
trace_t tr; |
|
|
|
UTIL_TraceLine( vecOrigin, vecOrigin + vecDirection * 16, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); |
|
|
|
if ( tr.surface.flags & SURF_SKY ) |
|
return; |
|
|
|
Vector vecEnd = vecOrigin - vecDirection * 128; |
|
|
|
shotRay.Init( vecOrigin, vecEnd ); |
|
|
|
CRagdollBoltEnumerator ragdollEnum( shotRay, vecOrigin ); |
|
::partition->EnumerateElementsAlongRay( PARTITION_CLIENT_RESPONSIVE_EDICTS, shotRay, false, &ragdollEnum ); |
|
|
|
CreateCrossbowBolt( vecOrigin, vecDirection ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &data - |
|
//----------------------------------------------------------------------------- |
|
void StickyBoltCallback( const CEffectData &data ) |
|
{ |
|
StickRagdollNow( data.m_vOrigin, data.m_vNormal ); |
|
} |
|
|
|
DECLARE_CLIENT_EFFECT( "BoltImpact", StickyBoltCallback ); |