bool CCollisionProperty::ShouldTouchTrigger( int triggerSolidFlags ) const
{
	// debris only touches certain triggers
	if ( GetCollisionGroup() == COLLISION_GROUP_DEBRIS )
	{
		if ( triggerSolidFlags & FSOLID_TRIGGER_TOUCH_DEBRIS )
			return true;

		return false;
	}

	// triggers don't touch other triggers (might be solid to other ents as well as trigger)
	if ( IsSolidFlagSet( FSOLID_TRIGGER ) )
		return false;

	return true;
}
void C_PhysPropClientside::Break()
{
	m_takedamage = DAMAGE_NO;
	
	IPhysicsObject *pPhysics = VPhysicsGetObject();

	Vector velocity;
	AngularImpulse angVelocity;
	Vector origin;
	QAngle angles;
	AddSolidFlags( FSOLID_NOT_SOLID );

	if ( pPhysics )
	{
		pPhysics->GetVelocity( &velocity, &angVelocity );
		pPhysics->GetPosition( &origin, &angles );
		pPhysics->RecheckCollisionFilter();
	}
	else
	{
		velocity = GetAbsVelocity();
		QAngleToAngularImpulse( GetLocalAngularVelocity(), angVelocity );
		origin = GetAbsOrigin();
		angles = GetAbsAngles();
	}

	breakablepropparams_t params( origin, angles, velocity, angVelocity );
	params.impactEnergyScale = m_impactEnergyScale;
	params.defCollisionGroup = GetCollisionGroup();
	if ( params.defCollisionGroup == COLLISION_GROUP_NONE )
	{
		// don't automatically make anything COLLISION_GROUP_NONE or it will
		// collide with debris being ejected by breaking
		params.defCollisionGroup = COLLISION_GROUP_INTERACTIVE;
	}

	// no damage/damage force? set a burst of 100 for some movement
	params.defBurstScale = 100;

	// spwan break chunks
	PropBreakableCreateAll( GetModelIndex(), pPhysics, params, this, -1, false );

	Release(); // destroy object
}
// Always explode immediately upon hitting anything
void CGERocket::ExplodeTouch( CBaseEntity *pOther )
{
	if ( !pOther->IsSolid() )
		return;

	// This also handles teammate collisions.
	if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) )
		return;

	trace_t tr;
	UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (m_vForward * 32), MASK_SOLID, this, GetCollisionGroup(), &tr );
	if( tr.surface.flags & SURF_SKY )
	{
		// Game Over, we hit the sky box, remove the rocket from the world (no explosion)
		StopSound("Weapon_RocketLauncher.Ignite");
		UTIL_Remove(this);
		return;
	}

	// If we are a bot, see if we hit our own NPC
	CGEBotPlayer *pBot = ToGEBotPlayer( GetThrower() );
	if ( pBot && pBot->GetNPC() == pOther )
		return;

	if (pOther != GetThrower())
	{
		// Check if they're a player, if they are deal out instant death.
		if (!m_bHitPlayer && (pOther->IsPlayer() || pOther->IsNPC()))
		{
			Vector playercenter = pOther->GetAbsOrigin() + Vector(0, 0, 38);
			Vector impactforce = playercenter - GetAbsOrigin();
			VectorNormalize(impactforce);

			impactforce *= 1000;

			CTakeDamageInfo rocketinfo(this, GetThrower(), impactforce, GetAbsOrigin(), 398.0f, DMG_BLAST);
			pOther->TakeDamage(rocketinfo);

			m_bHitPlayer = true; // Only deal one direct hit per projectile.
		}
		Explode();
	}
}
Exemple #4
0
void CASW_Rocket::MissileTouch( CBaseEntity *pOther )
{
	Assert( pOther );
	
	// Don't touch triggers (but DO hit weapons)
	if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER|FSOLID_VOLUME_CONTENTS) && pOther->GetCollisionGroup() != COLLISION_GROUP_WEAPON )
		return;

	if (pOther == GetOwnerEntity())
		return;

	// make sure we don't die on things we shouldn't
	if ( !ASWGameRules() || !ASWGameRules()->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) )
		return;

	if (asw_rocket_debug.GetBool())
		Msg("Rocket exploding on %d:%s\n", pOther->entindex(), pOther->GetClassname());
	//Msg("owner is %d:%s\n", GetOwnerEntity() ? GetOwnerEntity()->entindex() : -1,
		//GetOwnerEntity() ? GetOwnerEntity()->GetClassname() : "unknown");

	Explode();
}
bool CASW_Parasite::HasHeadroom()
{
	trace_t tr;
	UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, 1 ), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );

#if 0
	if( tr.fraction == 1.0f )
	{
		Msg("Headroom\n");
	}
	else
	{
		Msg("NO Headroom\n");
	}
#endif

	return (tr.fraction == 1.0);
}
int CASW_Parasite::RangeAttack1Conditions( float flDot, float flDist )
{
	if ( gpGlobals->curtime < m_flNextAttack )
		return 0;

	if ( ( GetFlags() & FL_ONGROUND ) == false )
		return 0;

	// This code stops lots of headcrabs swarming you and blocking you
	// whilst jumping up and down in your face over and over. It forces
	// them to back up a bit. If this causes problems, consider using it
	// for the fast headcrabs only, rather than just removing it.(sjb)
	if ( flDist < ASW_PARASITE_MIN_JUMP_DIST )
		return COND_TOO_CLOSE_TO_ATTACK;

	if ( flDist > ASW_PARASITE_MAX_JUMP_DIST )
		return COND_TOO_FAR_TO_ATTACK;

	// Make sure the way is clear!
	CBaseEntity *pEnemy = GetEnemy();
	if( pEnemy )
	{
		bool bEnemyIsBullseye = ( dynamic_cast<CNPC_Bullseye *>(pEnemy) != NULL );

		trace_t tr;
		AI_TraceLine( EyePosition(), pEnemy->EyePosition(), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );

		if ( tr.m_pEnt != GetEnemy() )
		{
			if ( !bEnemyIsBullseye || tr.m_pEnt != NULL )
				return COND_NONE;
		}

		if( GetEnemy()->EyePosition().z - 36.0f > GetAbsOrigin().z )
		{
			// Only run this test if trying to jump at a player who is higher up than me, else this 
			// code will always prevent a headcrab from jumping down at an enemy, and sometimes prevent it
			// jumping just slightly up at an enemy.
			Vector vStartHullTrace = GetAbsOrigin();
			vStartHullTrace.z += 1.0;

			Vector vEndHullTrace = GetEnemy()->EyePosition() - GetAbsOrigin();
			vEndHullTrace.NormalizeInPlace();
			vEndHullTrace *= 8.0;
			vEndHullTrace += GetAbsOrigin();

			AI_TraceHull( vStartHullTrace, vEndHullTrace,GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );

			if ( tr.m_pEnt != NULL && tr.m_pEnt != GetEnemy() )
			{
				return COND_TOO_CLOSE_TO_ATTACK;
			}
		}
	}

	return COND_CAN_RANGE_ATTACK1;
}
void CASW_Shotgun_Pellet_Predicted::PelletTouch( CBaseEntity *pOther )
{
	if (!pOther)
		return;

	if (pOther == m_pLastHit)		// don't damage the same alien twice
		return;

	if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
		return;

	// make sure we don't die on things we shouldn't
	if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup()))
		return;

	if ( pOther->m_takedamage != DAMAGE_NO )
	{
		trace_t	tr, tr2;
		tr = BaseClass::GetTouchTrace();
		Vector	vecNormalizedVel = GetAbsVelocity();
		VectorNormalize( vecNormalizedVel );
#ifdef GAME_DLL
		ClearMultiDamage();		

		if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() )
		{
			CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_NEVERGIB );
			dmgInfo.AdjustPlayerDamageInflictedForSkillLevel();
			CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
			dmgInfo.SetDamagePosition( tr.endpos );
			pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
		}
		else
		{
			CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_BULLET | DMG_NEVERGIB );
			CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
			dmgInfo.SetDamagePosition( tr.endpos );
			pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
		}

		ApplyMultiDamage();
#endif
		//Adrian: keep going through the glass.
		if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS )
			 return;

		// pellets should carry on through spawnable enemies?
		//IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pOther);
		//if (pSpawnable && asw_shotgun_pellets_pass.GetBool())
		//{
			//m_pLastHit = pOther;
			//return;
		//}

		SetAbsVelocity( Vector( 0, 0, 0 ) );

		// play body "thwack" sound
		EmitSound( "Weapon_Crossbow.BoltHitBody" );

		Vector vForward;

		AngleVectors( GetAbsAngles(), &vForward );
		VectorNormalize ( vForward );

		UTIL_TraceLine( GetAbsOrigin(),	GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 );
#ifdef GAME_DLL
		if ( tr2.fraction != 1.0f )
		{
//			NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 );
//			NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 );

			if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) )
			{
				CEffectData	data;

				data.m_vOrigin = tr2.endpos;
				data.m_vNormal = vForward;
				data.m_nEntIndex = tr2.fraction != 1.0f;
			
				//DispatchEffect( "BoltImpact", data );
			}
		}		
#endif
		SetTouch( NULL );
		SetThink( NULL );

		//KillEffects();
		//UTIL_Remove( this );
		//Release();
		SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove );
		SetNextThink( gpGlobals->curtime );
	}
	else
	{
		trace_t	tr;
		tr = BaseClass::GetTouchTrace();

		// See if we struck the world
		if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) )
		{
			//EmitSound( "Weapon_Crossbow.BoltHitWorld" );

			// if what we hit is static architecture, can stay around for a while.
			Vector vecDir = GetAbsVelocity();
			VectorNormalize( vecDir );
								
			SetMoveType( MOVETYPE_NONE );
		
			Vector vForward;

			AngleVectors( GetAbsAngles(), &vForward );
			VectorNormalize ( vForward );
#ifdef GAME_DLL
			CEffectData	data;

			data.m_vOrigin = tr.endpos;
			data.m_vNormal = vForward;
			data.m_nEntIndex = 0;
#endif
			//DispatchEffect( "BoltImpact", data );
			
			UTIL_ImpactTrace( &tr, DMG_BULLET );

			AddEffects( EF_NODRAW );
			SetTouch( NULL );
			//KillEffects();
			SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove );
			SetNextThink( gpGlobals->curtime + 2.0f );
			
			// Shoot some sparks
#ifdef GAME_DLL
			if ( UTIL_PointContents( GetAbsOrigin(), CONTENTS_WATER ) != CONTENTS_WATER)
			{
				g_pEffects->Sparks( GetAbsOrigin() );
			}
#endif
		}
		else
		{
			// Put a mark unless we've hit the sky
			if ( ( tr.surface.flags & SURF_SKY ) == false )
			{
				UTIL_ImpactTrace( &tr, DMG_BULLET );
			}
			//KillEffects();
			//UTIL_Remove( this );
			//Release();
			SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove );
			SetNextThink( gpGlobals->curtime );
		}
	}
}
void CGETKnife::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
{
	// Call the baseclass first so we don't interfere with the normal running of things
	BaseClass::VPhysicsCollision( index, pEvent );

	// Grab what we hit
	CBaseEntity *pOther = pEvent->pEntities[!index];

	if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
		return;

	if ( !PassServerEntityFilter( this, pOther) )
		return;

	if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) )
		return;

	trace_t tr;
	CollisionEventToTrace( index, pEvent, tr );

	Vector vecAiming = pEvent->preVelocity[index];
	VectorNormalize( vecAiming );

	if ( pOther->m_takedamage != DAMAGE_NO && (pOther->IsPlayer() || pOther->IsNPC()) )
	{
		ClearMultiDamage();

		CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), GetDamage(), DMG_SLASH | DMG_NEVERGIB );
		CalculateMeleeDamageForce( &dmgInfo, vecAiming, tr.endpos, TKNIFE_FORCE_SCALE );
		dmgInfo.SetDamagePosition( tr.endpos );

		if ( this->GetOwnerEntity() && this->GetOwnerEntity()->IsPlayer() )
		{
			CBasePlayer *pPlayer = ToBasePlayer( this->GetOwnerEntity() );
			dmgInfo.SetWeapon( pPlayer->Weapon_OwnsThisType( "weapon_throwing_knife" ) );
		}

		pOther->DispatchTraceAttack( dmgInfo, vecAiming, &tr );
		
		ApplyMultiDamage();

		PhysCallbackSetVelocity( pEvent->pObjects[index], vec3_origin );

		SetTouch( NULL );
		SetThink( NULL );

		PhysCallbackRemove( this->NetworkProp() );
	}
	else
	{
		if ( pOther->IsWorld() )
		{
			// We hit the world, we have to check if this is sky
			trace_t tr2;
			Vector origin;
			pEvent->pInternalData->GetContactPoint( origin );
			UTIL_TraceLine( origin, origin + (vecAiming * 4), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr2 );
			if ( tr2.surface.flags & SURF_SKY )
			{
				// We hit sky, remove us NOW
				SetTouch( NULL );
				SetThink( NULL );

				PhysCallbackRemove( this->NetworkProp() );
				return;
			}
		}

		m_bInAir = false;
		
		CollisionProp()->UseTriggerBounds( true, 24 );

		g_PostSimulationQueue.QueueCall( this, &CBaseEntity::SetOwnerEntity, (CBaseEntity*)NULL );

//		const CBaseEntity *host = te->GetSuppressHost();
//		te->SetSuppressHost( NULL );
//		StopParticleEffects( this );
//		te->SetSuppressHost( (CBaseEntity*)host );

		SetTouch( &CGETKnife::PickupTouch );
		SetThink( &CGETKnife::RemoveThink );

		g_PostSimulationQueue.QueueCall(this, &CBaseEntity::SetCollisionGroup, COLLISION_GROUP_DROPPEDWEAPON);

		SetNextThink( gpGlobals->curtime + 10.0f );
	}
}
void CGETKnife::DamageTouch( CBaseEntity *pOther )
{
	if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
		return;

	if ( !PassServerEntityFilter( this, pOther) )
		return;

	if ( !g_pGameRules->ShouldCollide( GetCollisionGroup(), pOther->GetCollisionGroup() ) )
		return;

	if (!pOther->IsPlayer() && !pOther->IsNPC())
		return;

	Vector vecAiming;
	VPhysicsGetObject()->GetVelocity( &vecAiming, NULL );
	VectorNormalize( vecAiming );

	trace_t tr;
	UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (vecAiming * 24), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );

	// We didn't hit the player again with our damage cast.  Do a cast to the player's center to get a proper hit.
	if (tr.m_pEnt != pOther)
	{
		Vector TargetVec = pOther->GetAbsOrigin();
		TargetVec.z = min(GetAbsOrigin().z, pOther->EyePosition().z); //Make sure we don't cast over their head.
		UTIL_TraceLine(GetAbsOrigin(), pOther->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr);
	}

// TEMPORARY DEBUGGING PURPOSES
//	DebugDrawLine( tr.startpos, tr.endpos, 0, 255, 0, true, 5.0f );
//	debugoverlay->AddSweptBoxOverlay( tr.startpos, tr.endpos, CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), GetAbsAngles(), 0, 0, 255, 100, 5.0f );
// END TEMPORARY

	// If our target can take damage and the trace actually hit our target
	if ( pOther->m_takedamage != DAMAGE_NO && tr.fraction < 1.0f && tr.m_pEnt == pOther )
	{
		ClearMultiDamage();

		CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), GetDamage(), DMG_SLASH | DMG_NEVERGIB );
		CalculateMeleeDamageForce( &dmgInfo, vecAiming, tr.endpos, TKNIFE_FORCE_SCALE );
		dmgInfo.SetDamagePosition( tr.endpos );

		if ( this->GetOwnerEntity() && this->GetOwnerEntity()->IsPlayer() )
		{
			CBasePlayer *pPlayer = ToBasePlayer( this->GetOwnerEntity() );
			dmgInfo.SetWeapon( pPlayer->Weapon_OwnsThisType( "weapon_knife_throwing" ) );
		}

		pOther->DispatchTraceAttack( dmgInfo, vecAiming, &tr );
		
		ApplyMultiDamage();

		SetAbsVelocity( vec3_origin );

		SetTouch( NULL );
		SetThink( NULL );

		PhysCallbackRemove( this->NetworkProp() );
	}
}
bool CNPC_Controller::OverrideMove( float flInterval )
{
	if (m_flGroundSpeed == 0)
	{
		m_flGroundSpeed = 100;
	}

	// ----------------------------------------------
	//	Select move target 
	// ----------------------------------------------
	CBaseEntity *pMoveTarget = NULL;
	if (GetTarget() != NULL )
	{
		pMoveTarget = GetTarget();
	}
	else if (GetEnemy() != NULL )
	{
		pMoveTarget		= GetEnemy();
	}

	// ----------------------------------------------
	//	Select move target position 
	// ----------------------------------------------
	Vector vMoveTargetPos(0,0,0);
	if (GetTarget())
	{
		vMoveTargetPos = GetTarget()->GetAbsOrigin();
	}
	else if (GetEnemy() != NULL)
	{
		vMoveTargetPos = GetEnemy()->GetAbsOrigin();
	}

	// -----------------------------------------
	//  See if we can fly there directly
	// -----------------------------------------
	if (pMoveTarget /*|| HaveInspectTarget()*/)
	{
		trace_t tr;

		if (pMoveTarget)
		{
			UTIL_TraceEntity( this, GetAbsOrigin(), vMoveTargetPos, 
				MASK_NPCSOLID_BRUSHONLY, pMoveTarget, GetCollisionGroup(), &tr);
		}
		else
		{
			UTIL_TraceEntity( this, GetAbsOrigin(), vMoveTargetPos, MASK_NPCSOLID_BRUSHONLY, &tr);
		}
/*
		float fTargetDist = (1-tr.fraction)*(GetAbsOrigin() - vMoveTargetPos).Length();
		if (fTargetDist > 50)
		{
			//SetCondition( COND_SCANNER_FLY_BLOCKED );
		}
		else
		{
			//SetCondition( COND_SCANNER_FLY_CLEAR );
		}
*/
	}

	// -----------------------------------------------------------------
	// If I have a route, keep it updated and move toward target
	// ------------------------------------------------------------------
	if (GetNavigator()->IsGoalActive())
	{
		if ( OverridePathMove( flInterval ) )
			return true;
	}
	else
	{
		//do nothing
		Stop();
		TaskComplete();
	}

	return true;
}
void CNPC_Dog::SetPlayerAvoidState( void )
{
	bool bIntersectingBoneFollowers = false;
	bool bIntersectingNPCBox = false;

	Vector vNothing;

	GetSequenceLinearMotion( GetSequence(), &vNothing );
	bool bIsMoving = ( IsMoving() || ( vNothing != vec3_origin ) );

	//If we are coming out of a script, check if we are stuck inside the player.
	if ( m_bPerformAvoidance || ( ShouldPlayerAvoid() && bIsMoving ) )
	{
		trace_t trace;
		Vector vMins, vMaxs;
		Vector vWorldMins, vWorldMaxs;
		Vector vPlayerMins, vPlayerMaxs;
		physfollower_t *pBone;
		int i;
		
		#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
			CBasePlayer *pLocalPlayer = UTIL_GetNearestPlayer(GetAbsOrigin()); 
		#else
			CBasePlayer *pLocalPlayer = AI_GetSinglePlayer();
		#endif //SecobMod__Enable_Fixed_Multiplayer_AI

		if ( pLocalPlayer )
		{
			vWorldMins = WorldAlignMins();
			vWorldMaxs = WorldAlignMaxs();

			vPlayerMins = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMins();
			vPlayerMaxs = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMaxs();

			// check if the player intersects the bounds of any of the bone followers
			for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
			{
				pBone = m_BoneFollowerManager.GetBoneFollower( i );
				if ( pBone && pBone->hFollower )
				{
					pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
					if ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) )
					{
						bIntersectingBoneFollowers = true;
						break;
					}
				}
			}

			bIntersectingNPCBox = IsBoxIntersectingBox( GetAbsOrigin() + vWorldMins, GetAbsOrigin() + vWorldMaxs, vPlayerMins, vPlayerMaxs );

			if ( ai_debug_avoidancebounds.GetBool() )
			{
				int iRed = ( bIntersectingNPCBox == true ) ? 255 : 0;

				NDebugOverlay::Box( GetAbsOrigin(), vWorldMins, vWorldMaxs, iRed, 0, 255, 64, 0.1 );

				// draw the bounds of the bone followers
				for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
				{
					pBone = m_BoneFollowerManager.GetBoneFollower( i );
					if ( pBone && pBone->hFollower )
					{
						pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
						iRed = ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) ) ? 255 : 0;

						NDebugOverlay::Box( vec3_origin, vMins, vMaxs, iRed, 0, 255, 64, 0.1 );
					}
				}
			}
		}
	}

	m_bPlayerAvoidState = ShouldPlayerAvoid();
	m_bPerformAvoidance = bIntersectingNPCBox || bIntersectingBoneFollowers;

	if ( GetCollisionGroup() == COLLISION_GROUP_NPC || GetCollisionGroup() == COLLISION_GROUP_NPC_ACTOR )
	{
		if ( bIntersectingNPCBox == true )
		{
			SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR );
		}
		else
		{
			SetCollisionGroup( COLLISION_GROUP_NPC );
		}

		if ( bIntersectingBoneFollowers == true )
		{
			MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC_ACTOR );
		}
		else
		{
			MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC );
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Should objects repel players on the same team
//-----------------------------------------------------------------------------
bool CBaseObject::ShouldPlayersAvoid( void )
{
	return ( GetCollisionGroup() == TFCOLLISION_GROUP_OBJECT );
}
void CRagdollProp::VPhysicsUpdate( IPhysicsObject *pPhysics )
{
	if ( m_lastUpdateTickCount == (unsigned int)gpGlobals->tickcount )
		return;

	m_lastUpdateTickCount = gpGlobals->tickcount;
	//NetworkStateChanged();

	matrix3x4_t boneToWorld[MAXSTUDIOBONES];
	QAngle angles;
	Vector surroundingMins, surroundingMaxs;
	if ( m_ragdoll.pGroup->IsInErrorState() )
	{
		RagdollSolveSeparation( m_ragdoll, this );
	}

	int i;
	for ( i = 0; i < m_ragdoll.listCount; i++ )
	{
		CBoneAccessor boneaccessor( boneToWorld );
		RagdollGetBoneMatrix( m_ragdoll, boneaccessor, i );
		
		Vector vNewPos;
		MatrixAngles( boneToWorld[m_ragdoll.boneIndex[i]], angles, vNewPos );
		m_ragPos.Set( i, vNewPos );
		m_ragAngles.Set( i, angles );
	}

	// BUGBUG: Use the ragdollmins/maxs to do this instead of the collides
	m_allAsleep = RagdollIsAsleep( m_ragdoll );

	// Don't scream after you've come to rest
	if ( m_allAsleep )
	{
		m_strSourceClassName = NULL_STRING;
	}
	
	// Interactive debris converts back to debris when it comes to rest
	if ( m_allAsleep && GetCollisionGroup() == COLLISION_GROUP_INTERACTIVE_DEBRIS )
	{
		SetCollisionGroup( COLLISION_GROUP_DEBRIS );
		RecheckCollisionFilter();
		SetContextThink( NULL, gpGlobals->curtime, s_pDebrisContext );
	}

	Vector vecFullMins, vecFullMaxs;
	vecFullMins = m_ragPos[0];
	vecFullMaxs = m_ragPos[0];
	for ( i = 0; i < m_ragdoll.listCount; i++ )
	{
		Vector mins, maxs;
		matrix3x4_t update;
		m_ragdoll.list[i].pObject->GetPositionMatrix( &update );
		TransformAABB( update, m_ragdollMins[i], m_ragdollMaxs[i], mins, maxs );
		for ( int j = 0; j < 3; j++ )
		{
			if ( mins[j] < vecFullMins[j] )
			{
				vecFullMins[j] = mins[j];
			}
			if ( maxs[j] > vecFullMaxs[j] )
			{
				vecFullMaxs[j] = maxs[j];
			}
		}
	}

	SetAbsOrigin( m_ragPos[0] );
	SetAbsAngles( vec3_angle );
	const Vector &vecOrigin = CollisionProp()->GetCollisionOrigin();
	CollisionProp()->AddSolidFlags( FSOLID_FORCE_WORLD_ALIGNED );
	CollisionProp()->SetSurroundingBoundsType( USE_COLLISION_BOUNDS_NEVER_VPHYSICS );
	SetCollisionBounds( vecFullMins - vecOrigin, vecFullMaxs - vecOrigin );
	CollisionProp()->MarkSurroundingBoundsDirty();

	PhysicsTouchTriggers();
}