Beispiel #1
0
void cRAI::DebugDrawShape(float3 centerPos, float lineLength, float width, int arrow, float yPosOffset, int lifeTime, int sides, int group)
{
	DebugDrawLine(centerPos, lineLength, 0, -lineLength/2,  lineLength/2, yPosOffset, lifeTime, arrow, width, group);
	DebugDrawLine(centerPos, lineLength, 1, -lineLength/2, -lineLength/2, yPosOffset, lifeTime, arrow, width, group);
	DebugDrawLine(centerPos, lineLength, 2,  lineLength/2, -lineLength/2, yPosOffset, lifeTime, arrow, width, group);
	DebugDrawLine(centerPos, lineLength, 3,  lineLength/2,  lineLength/2, yPosOffset, lifeTime, arrow, width, group);
}
Beispiel #2
0
void CMapzoneEdit::DrawReticle(Vector *pos, float retsize)
{
    Vector p1, p2, p3, p4, p5, p6;

    p1.x = pos->x + retsize;
    p1.y = pos->y;
    p1.z = pos->z;

    p2.x = pos->x - retsize;
    p2.y = pos->y;
    p2.z = pos->z;

    p3.x = pos->x;
    p3.y = pos->y + retsize;
    p3.z = pos->z;

    p4.x = pos->x;
    p4.y = pos->y - retsize;
    p4.z = pos->z;

    p5.x = pos->x;
    p5.y = pos->y;
    p5.z = pos->z + retsize;

    p6.x = pos->x;
    p6.y = pos->y;
    p6.z = pos->z - retsize;

    DebugDrawLine(p1, p2, 255, 0, 0, true, -1.0f);
    DebugDrawLine(p3, p4, 255, 0, 0, true, -1.0f);
    DebugDrawLine(p5, p6, 255, 0, 0, true, -1.0f);
}
Beispiel #3
0
void cRAI::DebugDrawShape(float3 CenterPos, float linelength, float width, int arrow, float yposoffset, int lifetime, int sides, int group)
{
	DebugDrawLine(CenterPos,linelength,0,-linelength/2,linelength/2,yposoffset,lifetime,arrow,width,group);
	DebugDrawLine(CenterPos,linelength,1,-linelength/2,-linelength/2,yposoffset,lifetime,arrow,width,group);
	DebugDrawLine(CenterPos,linelength,2,linelength/2,-linelength/2,yposoffset,lifetime,arrow,width,group);
	DebugDrawLine(CenterPos,linelength,3,linelength/2,linelength/2,yposoffset,lifetime,arrow,width,group);
}
void GraphicsWorld::DebugDrawAxes(const float3x4 &t, bool depthTest)
{
    float3 translate, scale;
    Quat rotate;
    t.Decompose(translate, rotate, scale);
    
    DebugDrawLine(translate, translate + rotate * float3(scale.x, 0.f, 0.f), 1, 0, 0, depthTest);
    DebugDrawLine(translate, translate + rotate * float3(0., scale.y, 0.f), 0, 1, 0, depthTest);
    DebugDrawLine(translate, translate + rotate * float3(0.f, 0.f, scale.z), 0, 0, 1, depthTest);
}
void GraphicsWorld::DebugDrawSphere(const float3& center, float radius, int vertices, const Color &clr, bool depthTest)
{
    if (vertices <= 0)
        return;
    
    Vector<float3> positions(vertices);

    Sphere sphere(center, radius);
    int actualVertices = sphere.Triangulate(&positions[0], 0, 0, vertices, true);
    for (int i = 0; i < actualVertices; i += 3)
    {
        DebugDrawLine(positions[i], positions[i + 1], clr, depthTest);
        DebugDrawLine(positions[i + 1], positions[i + 2], clr, depthTest);
        DebugDrawLine(positions[i + 2], positions[i], clr, depthTest);
    }
}
bool UTIL_ASW_BrushBlockingRoute( AI_Waypoint_t *pRoute, const int nCollisionMask, const int nCollisionGroup )
{
    if ( !pRoute )
        return false;

    AI_Waypoint_t *pLastPoint = pRoute;
    pRoute = pRoute->GetNext();
    trace_t tr;
    Vector vecShiftUp = Vector( 0, 0, 20 );

    while ( pRoute )
    {
        CTraceFilterSimple traceFilter( NULL, nCollisionGroup );
        UTIL_TraceLine( pLastPoint->GetPos() + vecShiftUp, pRoute->GetPos() + vecShiftUp,
                        nCollisionMask, &traceFilter, &tr );

        if ( asw_blink_debug.GetBool() )
        {
            DebugDrawLine( pLastPoint->GetPos() + vecShiftUp, pRoute->GetPos() + vecShiftUp, 255, 0, 0, true, 30.0f );
        }

        if ( tr.DidHit() )
        {
            return true;
        }

        pLastPoint = pRoute;
        pRoute = pRoute->GetNext();
    }

    return false;
}
// traces along an AI network route to see if a door is blocking the way
CASW_Door* UTIL_ASW_DoorBlockingRoute( AI_Waypoint_t *pRoute, bool bRequireLockedOrSealed )
{
    if ( !pRoute )
        return NULL;

    AI_Waypoint_t *pLastPoint = pRoute;
    pRoute = pRoute->GetNext();
    trace_t tr;
    Vector vecShiftUp = Vector( 0, 0, 20 );

    while ( pRoute )
    {
        CASW_Trace_Filter_Doors traceFilter( NULL, COLLISION_GROUP_NONE, bRequireLockedOrSealed );
        UTIL_TraceLine( pLastPoint->GetPos() + vecShiftUp, pRoute->GetPos() + vecShiftUp,
                        MASK_NPCSOLID, &traceFilter, &tr );

        if ( asw_blink_debug.GetBool() )
        {
            DebugDrawLine( pLastPoint->GetPos() + vecShiftUp, pRoute->GetPos() + vecShiftUp, 0, 0, 255, true, 30.0f );
        }

        if ( tr.DidHit() )
        {
            return dynamic_cast<CASW_Door*>(tr.m_pEnt);
        }

        pLastPoint = pRoute;
        pRoute = pRoute->GetNext();
    }

    return NULL;
}
void GraphicsWorld::DebugDrawPlane(const Plane &plane, const Color &clr, const float3 &refPoint, float uSpacing, float vSpacing, 
                               int uSegments, int vSegments, bool depthTest)
{
    float U0 = -uSegments * uSpacing / 2.f;
    float V0 = -vSegments * vSpacing / 2.f;

    float U1 = uSegments * uSpacing / 2.f;
    float V1 = vSegments * vSpacing / 2.f;

    for(int y = 0; y < vSegments; ++y)
        for(int x = 0; x < uSegments; ++x)
        {
            float u = U0 + x * uSpacing;
            float v = V0 + y * vSpacing;
            DebugDrawLine(plane.Point(U0, v, refPoint), plane.Point(U1, v, refPoint), clr, depthTest);
            DebugDrawLine(plane.Point(u, V0, refPoint), plane.Point(u, V1, refPoint), clr, depthTest);
        }
}
void GraphicsWorld::DebugDrawLight(const float3x4 &t, int lightType, float range, float spotAngle, const Color &clr, bool depthTest)
{
    float3 translate, scale;
    Quat rotate;
    t.Decompose(translate, rotate, scale);
    float3 lightDirection = rotate * float3(0.0f, 0.0f, 1.0f);
    switch (lightType)
    {
        // Point
    case 0:
        DebugDrawCircle(Circle(translate, float3(1.f, 0.f, 0.f), range), 8, clr, depthTest);
        DebugDrawCircle(Circle(translate, float3(0.f, 1.f, 0.f), range), 8, clr, depthTest);
        DebugDrawCircle(Circle(translate, float3(0.f, 0.f, 1.f), range), 8, clr, depthTest);
        break;
        
        // Spot
    case 1:
        {
            float3 endPoint = translate + range * lightDirection;
            float coneRadius = range * sinf(DegToRad(spotAngle));
            Circle spotCircle(endPoint, -lightDirection, coneRadius);
            
            DebugDrawCircle(Circle(endPoint, -lightDirection, coneRadius), 8, clr, depthTest);
            for (int i = 1; i <= 8; ++i)
                DebugDrawLine(translate, spotCircle.GetPoint(i * 2.f * 3.14f / 8), clr, depthTest);
        }
        break;
        
        // Directional
    case 2:
        {
            const float cDirLightRange = 10.f;
            float3 endPoint = translate + cDirLightRange * lightDirection;
            float3 offset = rotate * float3(1.f, 0.f, 0.f);
            DebugDrawLine(translate, endPoint, clr, depthTest);
            DebugDrawLine(translate + offset, endPoint + offset, clr, depthTest);
            DebugDrawLine(translate - offset, endPoint - offset, clr, depthTest);
        }
        break;
    }
}
Beispiel #10
0
void CASW_Path_Utils::DebugDrawRoute( const Vector &vecStartPos, AI_Waypoint_t *pWaypoint )
{
	Vector vecLastPos = vecStartPos;
	Msg(" Pathstart = %f %f %f\n", VectorExpand( g_vecPathStart ) );
	while ( pWaypoint )		
	{
		Msg("  waypoint = %f %f %f\n", VectorExpand( pWaypoint->GetPos() ) );
		DebugDrawLine( vecLastPos + Vector( 0, 0, 10 ) , pWaypoint->GetPos() + Vector( 0, 0, 10 ), 255, 0, 255, true, 30.0f );
		vecLastPos = pWaypoint->GetPos();
		pWaypoint = pWaypoint->GetNext();
	}
}
void ShowJointInfo(const NewtonCustomJoint* joint)
{
	NewtonJointRecord info;

	if (showContacts) {
		joint->GetInfo (&info);

		dMatrix bodyMatrix0;
		NewtonBodyGetMatrix (info.m_attachBody_0, &bodyMatrix0[0][0]);
		dMatrix matrix0 (*((dMatrix*) &info.m_attachmenMatrix_0[0]));
		matrix0 = matrix0 * bodyMatrix0;
		DebugDrawLine (matrix0.m_posit, matrix0.m_posit + matrix0.m_front, dVector (1, 0, 0));
		DebugDrawLine (matrix0.m_posit, matrix0.m_posit + matrix0.m_up, dVector (0, 1, 0));
		DebugDrawLine (matrix0.m_posit, matrix0.m_posit + matrix0.m_right, dVector (0, 0, 1));


		dMatrix bodyMatrix1;
		NewtonBodyGetMatrix (info.m_attachBody_1, &bodyMatrix1[0][0]);
		dMatrix matrix1 (*((dMatrix*) &info.m_attachmenMatrix_1[0]));
		matrix1 = matrix1 * bodyMatrix1;
		DebugDrawLine (matrix1.m_posit, matrix1.m_posit + matrix1.m_front, dVector (1, 0, 0));
		DebugDrawLine (matrix1.m_posit, matrix1.m_posit + matrix1.m_up,	   dVector (0, 1, 0));
		DebugDrawLine (matrix1.m_posit, matrix1.m_posit + matrix1.m_right, dVector (0, 0, 1));

	}

}
Beispiel #12
0
void CMapzoneEdit::Update()
{
    if (mom_zone_edit.GetBool())
    {
        if (!m_bEditing)
        {
            m_nBuildStage = BUILDSTAGE_NONE;
            m_bEditing = true;
        }
    }
    else
    {
        if (m_bEditing)
        {
            m_nBuildStage = BUILDSTAGE_NONE;
            m_bEditing = false;
        }

        return;
    }

    CBasePlayer *pPlayer = UTIL_GetLocalPlayer();

    if (!pPlayer) return;


    trace_t tr;
    Vector vecFwd;

    AngleVectors(pPlayer->EyeAngles(), &vecFwd);

    UTIL_TraceLine(pPlayer->EyePosition(), pPlayer->EyePosition() + vecFwd * m_flReticleDist, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_NONE, &tr);

    Vector vecAim = tr.endpos;

    if (mom_zone_grid.GetInt() > 0)
        VectorSnapToGrid(&vecAim, (float) mom_zone_grid.GetInt());


    if (m_nBuildStage >= BUILDSTAGE_START)
    {
        Vector vecP2, vecP3, vecP4;

        if (m_nBuildStage >= BUILDSTAGE_END)
        {
            vecP3 = m_vecBuildEnd;
        }
        else
        {
            vecP3 = vecAim;
        }

        vecP3[2] = m_vecBuildStart[2];

        // Bottom
        vecP2[0] = m_vecBuildStart[0];
        vecP2[1] = vecP3[1];
        vecP2[2] = m_vecBuildStart[2];

        vecP4[0] = vecP3[0];
        vecP4[1] = m_vecBuildStart[1];
        vecP4[2] = m_vecBuildStart[2];

        DebugDrawLine(m_vecBuildStart, vecP2, 255, 255, 255, true, -1.0f);
        DebugDrawLine(vecP2, vecP3, 255, 255, 255, true, -1.0f);
        DebugDrawLine(vecP3, vecP4, 255, 255, 255, true, -1.0f);
        DebugDrawLine(vecP4, m_vecBuildStart, 255, 255, 255, true, -1.0f);

        if (m_nBuildStage >= BUILDSTAGE_END)
        {
            Vector vecP5, vecP6, vecP8;

            m_vecBuildEnd[2] = SnapToGrid(m_vecBuildStart[2] + GetZoneHeightToPlayer(pPlayer), (float) mom_zone_grid.GetInt());

            // Top
            vecP5 = m_vecBuildStart;
            vecP5.z = m_vecBuildEnd[2];

            vecP6 = vecP2;
            vecP6.z = m_vecBuildEnd[2];

            vecP8 = vecP4;
            vecP8.z = m_vecBuildEnd[2];

            DebugDrawLine(vecP5, vecP6, 255, 255, 255, true, -1.0f);
            DebugDrawLine(vecP6, m_vecBuildEnd, 255, 255, 255, true, -1.0f);
            DebugDrawLine(m_vecBuildEnd, vecP8, 255, 255, 255, true, -1.0f);
            DebugDrawLine(vecP8, vecP5, 255, 255, 255, true, -1.0f);

            // Bottom to top
            DebugDrawLine(m_vecBuildStart, vecP5, 255, 255, 255, true, -1.0f);
            DebugDrawLine(vecP2, vecP6, 255, 255, 255, true, -1.0f);
            DebugDrawLine(vecP3, m_vecBuildEnd, 255, 255, 255, true, -1.0f);
            DebugDrawLine(vecP4, vecP8, 255, 255, 255, true, -1.0f);
        }
    }

    // Draw surface normal. Makes it a bit easier to see where reticle is hitting.
    if (tr.DidHit())
    {
        DebugDrawLine(vecAim, vecAim + tr.plane.normal * 24.0f, 0, 0, 255, true, -1.0f);
    }

    DrawReticle(&vecAim, (mom_zone_grid.GetInt() > 0) ? ((float) mom_zone_grid.GetInt() / 2.0f) : 8.0f);
}
void CBulletManager::SimulateBullet(CBullet& oBullet, float dt)
{
	Vector vecOriginal = oBullet.m_vecOrigin;

	Assert(oBullet.m_hShooter.Get());
	if (!oBullet.m_hShooter)
		return;

	bool bHasTraveledBefore = false;
	if (oBullet.m_flDistanceTraveled > 0)
		bHasTraveledBefore = true;

	// initialize these before the penetration loop, we'll need them to make our tracer after
	Vector vecTracerSrc = oBullet.m_vecOrigin;
	trace_t tr; // main enter bullet trace

	float flRange = dt;

	if (flRange < 0)
		flRange = 8000;

	bool bFullPenetrationDistance = false;

	Vector vecEnd = oBullet.m_vecOrigin + oBullet.m_vecDirection * flRange;

	int i;
	for (i = oBullet.m_iPenetrations; i < da_bullet_penetrations.GetInt(); i++)
	{
		CTraceFilterSimpleList tf(COLLISION_GROUP_NONE);
		tf.AddEntityToIgnore(oBullet.m_hShooter);

		for (int j = 0; j < oBullet.m_ahObjectsHit.Count(); j++)
			tf.AddEntityToIgnore(oBullet.m_ahObjectsHit[j]);

		UTIL_TraceLine( oBullet.m_vecOrigin, vecEnd, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &tf, &tr );

		if (da_bullet_debug.GetBool())
		{
#ifdef CLIENT_DLL
			DebugDrawLine(oBullet.m_vecOrigin + Vector(0, 0, 1), tr.endpos + Vector(0, 0, 1), 0, 255, 255, true, dt<0?10:0.1);
#else
			DebugDrawLine(oBullet.m_vecOrigin + Vector(0, 0, 1), tr.endpos + Vector(0, 0, 1), 255, 255, 0, true, dt<0?10:0.1);
#endif
		}

		Vector vecTraceEnd = tr.endpos;

		bool bBSPModel = tr.DidHitWorld();

		if (tr.allsolid)
		{
			oBullet.m_flDistanceTraveled += (oBullet.m_vecOrigin - vecEnd).Length();
			oBullet.m_vecOrigin = vecEnd;
			break; // We're inside something. Do nothing.
		}

		if ( sv_showimpacts.GetBool() && tr.fraction < 1.0f )
		{
#ifdef CLIENT_DLL
			// draw red client impact markers
			debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), QAngle( 0, 0, 0), 255,0,0,127, sv_showimpacts.GetFloat() );

			if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
			{
				C_BasePlayer *player = ToBasePlayer( tr.m_pEnt );
				player->DrawClientHitboxes( sv_showimpacts.GetFloat(), true );
			}
#else
			// draw blue server impact markers
			NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, sv_showimpacts.GetFloat() );

			if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
			{
				CBasePlayer *player = ToBasePlayer( tr.m_pEnt );
				player->DrawServerHitboxes( sv_showimpacts.GetFloat(), true );
			}
#endif
		}

		Assert(oBullet.m_iBulletType > 0);
		int iDamageType = DMG_BULLET | DMG_NEVERGIB | GetAmmoDef()->DamageType(oBullet.m_iBulletType);

		if (i == 0)
			iDamageType |= DMG_DIRECT;

		if (tr.startsolid)
		{
			trace_t tr2;

			UTIL_TraceLine( tr.endpos - oBullet.m_vecDirection, oBullet.m_vecOrigin, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr2 );

			// let's have a bullet exit effect if we penetrated a solid surface
			if (oBullet.m_bDoEffects && tr2.m_pEnt && tr2.m_pEnt->IsBSPModel())
				UTIL_ImpactTrace( &tr2, iDamageType );

			// ignore the entity we just hit for the next trace to avoid weird impact behaviors
			oBullet.m_ahObjectsHit.AddToTail(tr2.m_pEnt);
		}

		if ( tr.fraction == 1.0f )
		{
			oBullet.m_flDistanceTraveled += (oBullet.m_vecOrigin - vecEnd).Length();
			oBullet.m_vecOrigin = vecEnd;
			break; // we didn't hit anything, stop tracing shoot
		}

		weapontype_t eWeaponType = WT_NONE;

		CSDKWeaponInfo *pWeaponInfo = CSDKWeaponInfo::GetWeaponInfo(oBullet.m_eWeaponID);
		Assert(pWeaponInfo);
		if (pWeaponInfo)
			eWeaponType = pWeaponInfo->m_eWeaponType;

		float flDamageMultiplier = 1;
		float flMaxRange = 3000;

		// Power formula works like so:
		// pow( x, distance/y )
		// The damage will be at 1 when the distance is 0 units, and at
		// x% when the distance is y units, with a gradual decay approaching zero
		switch (eWeaponType)
		{
		case WT_RIFLE:
			flDamageMultiplier = 0.75f;
			flMaxRange = 3000;
			break;

		case WT_SHOTGUN:
			flDamageMultiplier = 0.40f;
			flMaxRange = 500;
			break;

		case WT_SMG:
			flDamageMultiplier = 0.50f;
			flMaxRange = 1000;
			break;

		case WT_PISTOL:
		default:
			flDamageMultiplier = 0.55f;
			flMaxRange = 1500;
			break;
		}

		flMaxRange *= oBullet.m_hShooter->m_Shared.ModifySkillValue(1, 0.5f, SKILL_MARKSMAN);

		//calculate the damage based on the distance the bullet travelled.
		oBullet.m_flDistanceTraveled += tr.fraction * flRange;

		float flCurrentDistance = oBullet.m_flDistanceTraveled;

		// First 500 units, no decrease in damage.
		if (eWeaponType == WT_SHOTGUN)
			flCurrentDistance -= 350;
		else
			flCurrentDistance -= 500;

		if (flCurrentDistance < 0)
			flCurrentDistance = 0;

		if (flCurrentDistance > flMaxRange)
			flCurrentDistance = flMaxRange;

		float flDistanceMultiplier = pow(flDamageMultiplier, (flCurrentDistance / flMaxRange));

		if( oBullet.m_bDoEffects )
		{
			// See if the bullet ended up underwater + started out of the water
			if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) )
			{
				CBaseEntity* pIgnore;
				if (oBullet.m_ahObjectsHit.Count())
					pIgnore = oBullet.m_ahObjectsHit.Tail();
				else
					pIgnore = oBullet.m_hShooter;

				trace_t waterTrace;
				UTIL_TraceLine( oBullet.m_vecOrigin, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), pIgnore, COLLISION_GROUP_NONE, &waterTrace );

				if( waterTrace.allsolid != 1 )
				{
					CEffectData	data;
					data.m_vOrigin = waterTrace.endpos;
					data.m_vNormal = waterTrace.plane.normal;
					data.m_flScale = random->RandomFloat( 8, 12 );

					if ( waterTrace.contents & CONTENTS_SLIME )
						data.m_fFlags |= FX_WATER_IN_SLIME;

					DispatchEffect( "gunshotsplash", data );
				}
			}
			else
			{
				//Do Regular hit effects

				// Don't decal nodraw surfaces
				if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) )
				{
					CBaseEntity *pEntity = tr.m_pEnt;
					//Tony; only while using teams do we check for friendly fire.
					if ( DAGameRules()->IsTeamplay() && pEntity && pEntity->IsPlayer() && (pEntity->GetBaseAnimating() && !pEntity->GetBaseAnimating()->IsRagdoll()) )
					{
						if ( pEntity->GetTeamNumber() != oBullet.m_hShooter->GetTeamNumber() )
							UTIL_ImpactTrace( &tr, iDamageType );
					}
					//Tony; non player, just go nuts,
					else
						UTIL_ImpactTrace( &tr, iDamageType );
				}
			}
		} // bDoEffects

		// add damage to entity that we hit

#ifdef GAME_DLL
		float flBulletDamage = oBullet.m_iBulletDamage * flDistanceMultiplier / (i+1);	// Each iteration the bullet drops in strength
		if (oBullet.m_hShooter->IsStyleSkillActive(SKILL_MARKSMAN))
			flBulletDamage = oBullet.m_iBulletDamage * flDistanceMultiplier / (i/2+1);	// Each iteration the bullet drops in strength but not nearly as much.

		ClearMultiDamage();

		CTakeDamageInfo info( oBullet.m_hShooter, oBullet.m_hShooter, oBullet.m_hWeapon, flBulletDamage, iDamageType );
		CalculateBulletDamageForce( &info, oBullet.m_iBulletType, oBullet.m_vecDirection, tr.endpos );
		tr.m_pEnt->DispatchTraceAttack( info, oBullet.m_vecDirection, &tr );

		oBullet.m_hShooter->TraceAttackToTriggers( info, tr.startpos, tr.endpos, oBullet.m_vecDirection );

		ApplyMultiDamage();
#else
		flDistanceMultiplier = flDistanceMultiplier; // Silence warning.
#endif

		if (tr.m_pEnt && !FStrEq(tr.m_pEnt->GetClassname(), "worldspawn"))
			oBullet.m_ahObjectsHit.AddToTail(tr.m_pEnt);

		float flPenetrationDistance;
		switch (eWeaponType)
		{
		case WT_RIFLE:
			flPenetrationDistance = 25;
			break;

		case WT_SHOTGUN:
			flPenetrationDistance = 5;
			break;

		case WT_SMG:
			flPenetrationDistance = 15;
			break;

		case WT_PISTOL:
		default:
			flPenetrationDistance = 15;
			break;
		}

		flPenetrationDistance = oBullet.m_hShooter->m_Shared.ModifySkillValue(flPenetrationDistance, 1, SKILL_MARKSMAN);

		Vector vecBackwards = tr.endpos + oBullet.m_vecDirection * flPenetrationDistance;
		if (tr.m_pEnt->IsBSPModel())
			UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr );
		else
			UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_HITBOX, NULL, COLLISION_GROUP_NONE, &tr );

		if (tr.startsolid)
		{
			bFullPenetrationDistance = true;
			break;
		}

		// Set up the next trace. One unit in the direction of fire so that we firmly embed
		// ourselves in whatever solid was hit, to make sure we don't hit it again on next trace.
		if (dt < 0 && bBSPModel)
		{
			UTIL_TraceLine( vecTraceEnd + oBullet.m_vecDirection, vecTraceEnd + oBullet.m_vecDirection * flPenetrationDistance, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr );

			if (tr.startsolid)
				oBullet.m_vecOrigin = tr.startpos + oBullet.m_vecDirection;
			else
				oBullet.m_vecOrigin = vecTraceEnd + oBullet.m_vecDirection;
		}
		else
			oBullet.m_vecOrigin = vecTraceEnd + oBullet.m_vecDirection;
	}

	oBullet.m_iPenetrations = i;

	// the bullet's done penetrating, let's spawn our particle system
	if (oBullet.m_bDoEffects && dt < 0)
		oBullet.m_hShooter->MakeTracer( oBullet.m_vecOrigin, tr, TRACER_TYPE_DEFAULT, !bHasTraveledBefore );

#ifdef CLIENT_DLL
	if (oBullet.m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE)
		ClientLeafSystem()->RenderableChanged( oBullet.m_hRenderHandle );
#endif

	if (bFullPenetrationDistance || oBullet.m_iPenetrations >= da_bullet_penetrations.GetInt())
		oBullet.Deactivate();

	if (dt < 0)
		oBullet.Deactivate();

	if (!bHasTraveledBefore && oBullet.m_flCurrAlpha == 0 && oBullet.m_flGoalAlpha == 0)
		oBullet.m_bActive = false;

	if (da_bullet_debug.GetBool())
	{
#ifdef CLIENT_DLL
		DebugDrawLine(vecOriginal, oBullet.m_vecOrigin, 0, 0, 255, true, dt<0?10:0.1);
#else
		DebugDrawLine(vecOriginal, oBullet.m_vecOrigin, 255, 0, 0, true, dt<0?10:0.1);
#endif
	}
}