Simulated Bullets: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
Line 149: Line 149:
#include "shot_manipulator.h"
#include "shot_manipulator.h"
#pragma warning(disable:4800)
#pragma warning(disable:4800)
#ifdef CLIENT_DLL
 
#ifdef CLIENT_DLL//-------------------------------------------------
#include "c_te_effect_dispatch.h"
#include "engine/ivdebugoverlay.h"
ConVar g_cl_debug_bullets( "g_cl_debug_bullets", "0", FCVAR_CHEAT );
ConVar g_cl_debug_bullets( "g_cl_debug_bullets", "0", FCVAR_CHEAT );
C_BulletManager *g_pBulletManager = new C_BulletManager();
C_BulletManager *g_pBulletManager = new C_BulletManager();
#else
#else//-------------------------------------------------------------
#include "soundent.h"
#include "player_pickup.h"
ConVar g_debug_bullets( "g_debug_bullets", "0", FCVAR_CHEAT );
ConVar g_debug_bullets( "g_debug_bullets", "0", FCVAR_CHEAT );
CBulletManager *g_pBulletManager;
CBulletManager *g_pBulletManager;
#endif
#endif//------------------------------------------------------------


LINK_ENTITY_TO_CLASS( bullet_manager, CBulletManager );
// memdbgon must be the last include file in a .cpp file!!!
CBulletManager::CBulletManager()
#include "tier0/memdbgon.h"
static void BulletSpeedModifierCallback(ConVar *var, const char *pOldString)
{
{
Q_memset( m_rgBullets, 0, MAX_BULLETS );
if(var->GetFloat()==0.0f)
m_iLastBullet = -1;
var->Revert();
}
}
#ifdef CLIENT_DLL
ConVar sv_bullet_speed_modifier( "sv_bullet_speed_modifier", "700.000000", (FCVAR_ARCHIVE | FCVAR_REPLICATED),
#include "engine/ivdebugoverlay.h"
"Density/(This Value) * (Distance Penetrated) = (Change in Speed)",
CON_COMMAND_F(createbullet,NULL,FCVAR_CHEAT)
BulletSpeedModifierCallback );
 
static void BulletStopSpeedCallback(ConVar *var, const char *pOldString)
{
{
Assert(ClientBulletManager());
float val = var->GetFloat();
if(!ClientBulletManager())
if(val==0.0f||(val<0.0f&&(val!=BUTTER_MODE||val!=ONE_HIT_MODE)))
return;
var->Revert();
Vector dir;
g_pLocalPlayer->EyeVectors(&dir);
FireBulletsInfo_t info(1,g_pLocalPlayer->EyePosition(),dir,vec3_origin,0,0);
info.m_pAttacker = g_pLocalPlayer;
engine->ServerCmd(VarArgs("createbullet_s %f\n",gpGlobals->curtime));
ClientBulletManager()->AddBullet(info,0.0f);
}
}
#else
ConVar sv_bullet_stop_speed( "sv_bullet_stop_speed", "40.000000", (FCVAR_ARCHIVE | FCVAR_REPLICATED),
CON_COMMAND_F(createbullet_s,NULL,FCVAR_CHEAT)
"Speed at which to remove the bullet from the bullet queue\n-1 is butter mode\n-2 is 1 hit mode",
BulletStopSpeedCallback );
 
LINK_ENTITY_TO_CLASS( bullet_manager, CBulletManager );
CBulletManager::CBulletManager()
{
{
Assert(BulletManager());
m_pBullets.SetSize(16);
if(!BulletManager())
m_pBullets.SetGrowSize(16);
return;
#ifdef CLIENT_DLL
CBasePlayer *pPlayer = UTIL_GetCommandClient();
ClientThink();
if(!pPlayer)
#endif
return;
Vector dir;
pPlayer->EyeVectors(&dir);
FireBulletsInfo_t info(1,pPlayer->EyePosition(),dir,vec3_origin,0,0);
info.m_pAttacker = pPlayer;
float lag = gpGlobals->curtime - atof(engine->Cmd_Argv(1));
if(lag<0.0f||lag==gpGlobals->curtime)
lag=0.0f;
BulletManager()->AddBullet(info,lag);
}
}
#endif
#ifdef GAME_DLL
void CBulletManager::Spawn(void)
void CBulletManager::Spawn(void)
{
{
g_pBulletManager = this;
#ifdef CLIENT_DLL
ClientThink();
#else
Think();
Think();
}
#endif
#endif
}
#define REMOVE_BULLET_AND_END(x) BulletManager()->RemoveBullet(x);return
void CBulletManager::SimulateBullet(int index, float time/*=1.0f 100ths of sec*/)
void CSimulatedBullet::SimulateBullet(int index, float flTime/*=1.0f 100ths of sec*/)
{
{
#define CUR m_rgBullets[index]
Vector vecEntryPosition;
Vector vecExitPosition;
float flPenetrationDistance = 0.0f;
trace_t trace, trace_back;
trace_t trace, trace_back;
Vector m_vOldOrigin(CUR.m_vOrigin);
Vector m_vOldOrigin(m_vecOrigin);
Vector m_vTraceStart(CUR.m_vOrigin);
Vector m_vTraceStart(m_vecOrigin);
DevMsg("BulletSpeed %f\n",CUR.m_flBulletSpeed);
Vector vecNewRay = CUR.m_Bullet.m_vecDirShooting * CUR.m_flBulletSpeed * time;
Vector vecNewRay = m_vecDirShooting * m_flBulletSpeed * flTime;
CUR.m_vOrigin += vecNewRay;//in/100th of a sec * 100th of a sec
 
bool bInWater = UTIL_PointContents(CUR.m_vOrigin)&MASK_SPLITAREAPORTAL;
DevMsg("Bullet %i Speed %f\n",index,m_flBulletSpeed);
if(CUR.m_bWasInWater!=bInWater)
m_vecOrigin += vecNewRay;//in/100th of a sec * 100th of a sec
bool bInWater = UTIL_PointContents(m_vecOrigin)&MASK_SPLITAREAPORTAL;
if(!IsInWorld())
{
REMOVE_BULLET_AND_END(index);
}
if(m_bWasInWater!=bInWater)
{
{
#ifdef CLIENT_DLL
#ifdef CLIENT_DLL
Line 228: Line 230:
#endif //CLIENT_DLL
#endif //CLIENT_DLL
}
}
CUR.m_bWasInWater = bInWater;
Vector vecEntryPosition;
#ifdef GAME_DLL
Vector vecExitPosition;
if(g_debug_bullets.GetBool())
float flPenetrationDistance = 0.0f;
{
NDebugOverlay::Line( m_vOldOrigin, m_vecOrigin, 255, 255, 255, true, 10.0f );
}
#else //!GAME_DLL
if(g_cl_debug_bullets.GetBool())
{
debugoverlay->AddLineOverlay( m_vOldOrigin, m_vecOrigin, 255, 0, 0, true, 10.0f );
}
#endif
m_bWasInWater = bInWater;
float flBulletStopSpeed = sv_bullet_stop_speed.GetFloat();
int iBulletStopSpeedCase = (int)flBulletStopSpeed;
do
do
{
{
UTIL_TraceLine( m_vTraceStart, CUR.m_vOrigin, MASK_SHOT, CUR.m_pTwoEnts, &trace );
UTIL_TraceLine( m_vTraceStart, m_vecOrigin, MASK_SHOT, m_pTwoEnts, &trace );
if(!(trace.surface.flags&SURF_SKY))
if(!(trace.surface.flags&SURF_SKY))
{
{
if(trace.allsolid)//in solid
if(trace.allsolid)//in solid
{
{
trace.endpos = CUR.m_vOrigin;
trace.endpos = m_vecOrigin;
trace.fraction = 1.0f;
trace.fraction = 1.0f;
CUR.m_flBulletSpeed -= CUR.m_flBulletSpeed * CUR.m_flEntryDensity / 1000.0f;
switch(iBulletStopSpeedCase)
{
case BUTTER_MODE:
{
//Do nothing to bullet speed
break;
}
case ONE_HIT_MODE:
{
REMOVE_BULLET_AND_END(index);
}
default:
{
m_flBulletSpeed -= m_flBulletSpeed * m_flEntryDensity / sv_bullet_speed_modifier.GetFloat();
break;
}
}
break;
break;
}
}
Line 251: Line 280:
vecExitPosition = trace.fractionleftsolid * vecNewRay + m_vTraceStart;
vecExitPosition = trace.fractionleftsolid * vecNewRay + m_vTraceStart;
flPenetrationDistance = vecEntryPosition.DistTo(vecExitPosition);
flPenetrationDistance = vecEntryPosition.DistTo(vecExitPosition);
CUR.m_flBulletSpeed -= flPenetrationDistance * CUR.m_flEntryDensity / 1000.0f;
switch(iBulletStopSpeedCase)
{
case BUTTER_MODE:
{
//Do nothing to bullet speed
break;
}
case ONE_HIT_MODE:
{
REMOVE_BULLET_AND_END(index);
}
default:
{
m_flBulletSpeed -= flPenetrationDistance * m_flEntryDensity / sv_bullet_speed_modifier.GetFloat();
break;
}
}
}
}
else if(trace.fraction!=1.0f)//hit solid
else if(trace.fraction!=1.0f)//hit solid
{
{
vecEntryPosition = trace.endpos;
#ifdef GAME_DLL
int soundEntChannel = ( m_nFlags&FIRE_BULLETS_TEMPORARY_DANGER_SOUND ) ? SOUNDENT_CHANNEL_BULLET_IMPACT : SOUNDENT_CHANNEL_UNSPECIFIED;
CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, vecEntryPosition, 200, 0.5, m_hCaller, soundEntChannel );
#endif
if(FStrEq(trace.surface.name,"tools/toolsblockbullets"))
if(FStrEq(trace.surface.name,"tools/toolsblockbullets"))
{
{
RemoveBullet(index);
REMOVE_BULLET_AND_END(index);
return;
}
}
#ifdef CLIENT_DLL
#ifdef CLIENT_DLL
CEffectData data;
data.m_vStart = trace.startpos;
data.m_vOrigin = trace.endpos;
data.m_nDamageType = m_nDamageType;
//Clientside ragdolls' locations cannot be determined by the server
DispatchEffect( "RagdollImpact", data );
//TODO: surface impact stuff
//TODO: surface impact stuff
#endif //CLIENT_DLL
#endif //CLIENT_DLL
CUR.m_flEntryDensity = physprops->GetSurfaceData(trace.surface.surfaceProps)->physics.density;
m_flEntryDensity = physprops->GetSurfaceData(trace.surface.surfaceProps)->physics.density;
vecEntryPosition = trace.endpos;
#ifdef GAME_DLL
#ifdef GAME_DLL
if(trace.DidHitNonWorldEntity())
if(trace.DidHitNonWorldEntity())
{
{
if(CUR.m_pIgnoreList->ShouldHitEntity(trace.m_pEnt,MASK_SHOT))
if(m_pIgnoreList->ShouldHitEntity(trace.m_pEnt,MASK_SHOT))
{
{
CUR.m_pIgnoreList->AddEntityToIgnore(trace.m_pEnt);
m_pIgnoreList->AddEntityToIgnore(trace.m_pEnt);
//TODO: entity impact stuff
EntityImpact(trace.m_pEnt);
}
}
}
}
#endif //GAME_DLL
#endif
if(iBulletStopSpeedCase==ONE_HIT_MODE)
{
REMOVE_BULLET_AND_END(index);
}
}
}
}
}
m_vTraceStart = trace.endpos + CUR.m_Bullet.m_vecDirShooting;
m_vTraceStart = trace.endpos + m_vecDirShooting;
}while(trace.endpos!=CUR.m_vOrigin&&CUR.m_flBulletSpeed>0.0f);
}while(trace.endpos!=m_vecOrigin&&m_flBulletSpeed>flBulletStopSpeed);
 


#ifdef GAME_DLL
if(m_flBulletSpeed<=flBulletStopSpeed)
if(g_debug_bullets.GetBool())
{
{
NDebugOverlay::Line(m_vOldOrigin,CUR.m_vOrigin, 255, 255, 255, true, 10.0f );
REMOVE_BULLET_AND_END(index);
}
}
#else //!GAME_DLL
}
if(g_cl_debug_bullets.GetBool())
#ifdef GAME_DLL
void CSimulatedBullet::EntityImpact(CBaseEntity *pHit)
{
//TODO: entity impact stuff
if ( GetAmmoDef()->Flags(m_iAmmoType) & AMMO_FORCE_DROP_IF_CARRIED )
{
{
debugoverlay->AddLineOverlay(m_vTraceStart, CUR.m_vOrigin, 255, 0, 0, true, 10.0f);
// Make sure if the player is holding this, he drops it
Pickup_ForcePlayerToDropThisObject( pHit );
}
}
}
#endif
#endif
if(CUR.m_flBulletSpeed<=0.0f||!IsInWorld(index))
RemoveBullet(index);
#undef CUR
}
#ifdef CLIENT_DLL
#ifdef CLIENT_DLL
void CBulletManager::ClientThink(void)
void CBulletManager::ClientThink(void)
Line 302: Line 362:
#endif
#endif
{
{
for(int x=0;x<=m_iLastBullet;x++)
for(int x=0;x<=m_pBullets.Count();x++)
{
{
SimulateBullet(x);
m_pBullets[x]->SimulateBullet(x);
}
}
#ifdef CLIENT_DLL
#ifdef CLIENT_DLL
SetNextClientThink
ClientThinkList()->SetNextClientThink( GetClientHandle(), gpGlobals->curtime + 0.01f );
#else
#else
SetNextThink
SetNextThink( gpGlobals->curtime + 0.01f );
#endif
#endif
( gpGlobals->curtime + 0.01f );
}
}
void CBulletManager::AddBullet(FireBulletsInfo_t &bullet,float lagCompensation)
void CBulletManager::AddBullet(CSimulatedBullet *pBullet)
{
{
if (bullet.m_iAmmoType == -1)
if (pBullet->AmmoIndex() == -1)
{
{
DevMsg("ERROR: Undefined ammo type!\n");
DevMsg("ERROR: Undefined ammo type!\n");
return;
return;
}
}
if(m_iLastBullet==MAX_BULLETS-1)//256 simultaneous bullets in the air is mayhem
int index = m_pBullets.AddToTail(pBullet);
{//let's do something reckless on bullet mayhem
DevMsg( "Bullet Created (%i) LagCompensation %f\n",index, pBullet->LagCompensation() );
Assert(m_iLastBullet!=MAX_BULLETS-1);
 
Warning("Bullet queue filled (Removing bullet #0)\n");
if(m_pBullets[index]->LagCompensation()!=0.0f)
RemoveBullet(0);
m_pBullets[index]->SimulateBullet(index, pBullet->LagCompensation());
}
else
m_iLastBullet++;
DevMsg("Bullet Created (%i) LagCompensation %f\n",m_iLastBullet,lagCompensation);
CShotManipulator Manipulator( bullet.m_vecDirShooting );
bullet.m_vecDirShooting = Manipulator.ApplySpread(bullet.m_vecSpread);
m_rgBullets[m_iLastBullet] = SimulatedBullet_t(bullet,lagCompensation);
if(lagCompensation!=0.0f)
SimulateBullet(m_iLastBullet, lagCompensation*100);
}
}
void CBulletManager::RemoveBullet(int index)
void CBulletManager::RemoveBullet(int index)
{
{
if(m_iLastBullet!=index)
m_pBullets.Remove(index);
{
m_rgBullets[index].DeletePointers();
m_rgBullets[index] = m_rgBullets[m_iLastBullet];
DevMsg("Bullet #%i Destroyed; Replacing with #%i\n",index, m_iLastBullet);
}
else
{
m_rgBullets[index].DeletePointers();
DevMsg("Bullet #%i Destroyed\n",index);
}
m_rgBullets[m_iLastBullet] = SimulatedBullet_t();
m_iLastBullet--;
}
inline bool CBulletManager::IsInWorld(int index)
{
if (m_rgBullets[index].m_vOrigin.x >= MAX_COORD_INTEGER) return false;
if (m_rgBullets[index].m_vOrigin.y >= MAX_COORD_INTEGER) return false;
if (m_rgBullets[index].m_vOrigin.z >= MAX_COORD_INTEGER) return false;
if (m_rgBullets[index].m_vOrigin.x <= MIN_COORD_INTEGER) return false;
if (m_rgBullets[index].m_vOrigin.y <= MIN_COORD_INTEGER) return false;
if (m_rgBullets[index].m_vOrigin.z <= MIN_COORD_INTEGER) return false;
return true;
}</pre>
}</pre>
====hl2mp_gamerules.cpp====
====hl2mp_gamerules.cpp====
Change <code>GetAmmoDef</code> to the following:
Change <code>GetAmmoDef</code> to the following:

Revision as of 19:38, 22 November 2005

Preface

Basically, with simulated bullets, the aspects of physics are going to tried to be captured by simulating them in batch simulation code. So far the code is all server-side and is later expected to be client-side simulated with similar code.


Note.pngNote:This code is a work in progress. Feel free to make helpful changes. To test the code, you can bind a key to createbullet ingame and that will fire a bullet from your view with a line drawn along its path.

Body

This code is WIP by ts2do

game_shared

bullet_manager.h

#include "ammodef.h"
#define BULLET_SPEED 240//inches per hundredths of a second
#define BUTTER_MODE -1
#define ONE_HIT_MODE -2

#ifdef CLIENT_DLL
class C_BulletManager;
extern C_BulletManager *g_pBulletManager;
#define CBulletManager C_BulletManager


#else //!CLIENT_DLL
class CBulletManager;
extern CBulletManager *g_pBulletManager;
#endif //CLIENT_DLL

inline CBulletManager *BulletManager()
{
	return g_pBulletManager;
}

extern ConVar g_debug_bullets;
class CSimulatedBullet
{
public:
	CSimulatedBullet()
	{
		m_vecOrigin.Init();
		m_vecDirShooting.Init();
		m_flInitialBulletSpeed = m_flBulletSpeed = BULLET_SPEED;
		m_flEntryDensity = m_flLagCompensation = 0.0f;
		m_nFlags = (FireBulletsFlags_t)0;
		m_iDamage = m_iAmmoType = m_nDamageType = 0;
	}
	CSimulatedBullet( CBaseEntity *pCaller, CBaseEntity *pAttacker, CBaseEntity *pAdditionalIgnoreEnt,
						int ammoType, int damageType, int nFlags, Vector &vecDirShooting,
						Vector &vecOrigin, int iDamage, float flLagCompensation )
	{
		m_nFlags = (FireBulletsFlags_t)nFlags;
		m_iAmmoType = ammoType;
		m_nDamageType = damageType;
		m_vecOrigin = vecOrigin;
		m_vecDirShooting = vecDirShooting;
		m_flInitialBulletSpeed = m_flBulletSpeed = GetAmmoDef()->GetAmmoOfIndex(ammoType)->flFeetPerSecond * 0.12;
		//m_flInitialBulletSpeed = m_flBulletSpeed = BULLET_SPEED;
		m_flEntryDensity = 0.0f;
		m_flLagCompensation = 100*flLagCompensation;
		m_iDamage = iDamage;
		m_hCaller = pCaller;
#ifndef CLIENT_DLL
		m_pIgnoreList = new CTraceFilterSimpleList(COLLISION_GROUP_NONE);
		m_pIgnoreList->AddEntityToIgnore(pAttacker);
		if(pAdditionalIgnoreEnt!=NULL)
			m_pIgnoreList->AddEntityToIgnore(pAdditionalIgnoreEnt);
#endif
		m_pTwoEnts = new CTraceFilterSkipTwoEntities(pAttacker,pAdditionalIgnoreEnt,COLLISION_GROUP_NONE);
	}
	~CSimulatedBullet()
	{
#ifndef CLIENT_DLL
		//leave the compensation considerations because they're entities
		delete m_pIgnoreList;
#endif
		delete m_pTwoEnts;
	}
	inline float BulletSpeedRatio(void)
	{
		return m_flBulletSpeed/m_flInitialBulletSpeed;
	}
#ifdef GAME_DLL
	void EntityImpact(CBaseEntity *pHit);
#endif
	inline bool IsInWorld(void)
	{
		if (m_vecOrigin.x >= MAX_COORD_INTEGER) return false;
		if (m_vecOrigin.y >= MAX_COORD_INTEGER) return false;
		if (m_vecOrigin.z >= MAX_COORD_INTEGER) return false;
		if (m_vecOrigin.x <= MIN_COORD_INTEGER) return false;
		if (m_vecOrigin.y <= MIN_COORD_INTEGER) return false;
		if (m_vecOrigin.z <= MIN_COORD_INTEGER) return false;
		return true;
	}
	void SimulateBullet(int index,float flTime=1.0f);
	inline float LagCompensation(void)
	{
		return m_flLagCompensation;
	}
	inline int AmmoIndex(void)
	{
		return m_iAmmoType;
	}
private:
	bool m_bWasInWater;

	CTraceFilterSkipTwoEntities *m_pTwoEnts;
#ifndef CLIENT_DLL
	CTraceFilterSimpleList *m_pIgnoreList;//already hit
	CUtlVector<CBaseEntity *> m_pCompensationConsiderations;//Couldn't resist
#endif

	EHANDLE m_hCaller;

	FireBulletsFlags_t m_nFlags;

	float m_flBulletSpeed;
	float m_flEntryDensity;
	float m_flInitialBulletSpeed;
	float m_flLagCompensation;

	int m_iAmmoType;
	int m_iDamage;
	int m_nDamageType;

	Vector m_vecDirShooting;
	Vector m_vecOrigin;
};
class CBulletManager : public CBaseEntity
{
	DECLARE_CLASS( CBulletManager, CBaseEntity );
public:
	CUtlVector<CSimulatedBullet*> m_pBullets;

	CBulletManager();
#ifdef CLIENT_DLL
	void ClientThink(void);
#else
	void Spawn(void);
	void Think(void);
#endif
	void AddBullet(CSimulatedBullet *pBullet);
	void RemoveBullet(int index);
};

bullet_manager.cpp

#include "cbase.h"
#include "util_shared.h"
#include "bullet_manager.h"
#include "shot_manipulator.h"
#pragma warning(disable:4800)

#ifdef CLIENT_DLL//-------------------------------------------------
#include "c_te_effect_dispatch.h"
#include "engine/ivdebugoverlay.h"
ConVar g_cl_debug_bullets( "g_cl_debug_bullets", "0", FCVAR_CHEAT );
C_BulletManager *g_pBulletManager = new C_BulletManager();
#else//-------------------------------------------------------------
#include "soundent.h"
#include "player_pickup.h"
ConVar g_debug_bullets( "g_debug_bullets", "0", FCVAR_CHEAT );
CBulletManager *g_pBulletManager;
#endif//------------------------------------------------------------

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static void BulletSpeedModifierCallback(ConVar *var, const char *pOldString)
{
	if(var->GetFloat()==0.0f)
		var->Revert();
}
ConVar sv_bullet_speed_modifier( "sv_bullet_speed_modifier", "700.000000", (FCVAR_ARCHIVE | FCVAR_REPLICATED),
								"Density/(This Value) * (Distance Penetrated) = (Change in Speed)",
								BulletSpeedModifierCallback );

static void BulletStopSpeedCallback(ConVar *var, const char *pOldString)
{
	float val = var->GetFloat();
	if(val==0.0f||(val<0.0f&&(val!=BUTTER_MODE||val!=ONE_HIT_MODE)))
		var->Revert();
}
ConVar sv_bullet_stop_speed( "sv_bullet_stop_speed", "40.000000", (FCVAR_ARCHIVE | FCVAR_REPLICATED),
							"Speed at which to remove the bullet from the bullet queue\n-1 is butter mode\n-2 is 1 hit mode",
							BulletStopSpeedCallback );

LINK_ENTITY_TO_CLASS( bullet_manager, CBulletManager );
CBulletManager::CBulletManager()
{
	m_pBullets.SetSize(16);
	m_pBullets.SetGrowSize(16);
#ifdef CLIENT_DLL
	ClientThink();
#endif
}
#ifdef GAME_DLL
void CBulletManager::Spawn(void)
{
	Think();
}
#endif
#define REMOVE_BULLET_AND_END(x) BulletManager()->RemoveBullet(x);return
void CSimulatedBullet::SimulateBullet(int index, float flTime/*=1.0f 100ths of sec*/)
{
	Vector vecEntryPosition;
	Vector vecExitPosition;
	float flPenetrationDistance = 0.0f;
	trace_t trace, trace_back;
	Vector m_vOldOrigin(m_vecOrigin);
	Vector m_vTraceStart(m_vecOrigin);
	
	Vector vecNewRay = m_vecDirShooting * m_flBulletSpeed * flTime;

	DevMsg("Bullet %i Speed %f\n",index,m_flBulletSpeed);
	m_vecOrigin += vecNewRay;//in/100th of a sec * 100th of a sec
	bool bInWater = UTIL_PointContents(m_vecOrigin)&MASK_SPLITAREAPORTAL;
	if(!IsInWorld())
	{
		REMOVE_BULLET_AND_END(index);
	}
	if(m_bWasInWater!=bInWater)
	{
#ifdef CLIENT_DLL
		//TODO: water impact effect
		//CBaseEntity::HandleShotImpactingWater
#endif //CLIENT_DLL
	}
	if(bInWater)
	{
#ifdef CLIENT_DLL
		//TODO: 1 bubble clientside
#endif //CLIENT_DLL
	}
	
#ifdef GAME_DLL
	if(g_debug_bullets.GetBool())
	{
		NDebugOverlay::Line( m_vOldOrigin, m_vecOrigin, 255, 255, 255, true, 10.0f );
	}
#else //!GAME_DLL
	if(g_cl_debug_bullets.GetBool())
	{
		debugoverlay->AddLineOverlay( m_vOldOrigin, m_vecOrigin, 255, 0, 0, true, 10.0f );
	}
#endif
	m_bWasInWater = bInWater;
	float flBulletStopSpeed = sv_bullet_stop_speed.GetFloat();
	int iBulletStopSpeedCase = (int)flBulletStopSpeed;
	do
	{
		UTIL_TraceLine( m_vTraceStart, m_vecOrigin, MASK_SHOT, m_pTwoEnts, &trace );
		if(!(trace.surface.flags&SURF_SKY))
		{
			if(trace.allsolid)//in solid
			{
				trace.endpos = m_vecOrigin;
				trace.fraction = 1.0f;
				switch(iBulletStopSpeedCase)
				{
					case BUTTER_MODE:
					{
						//Do nothing to bullet speed
						break;
					}
					case ONE_HIT_MODE:
					{
						REMOVE_BULLET_AND_END(index);
					}
					default:
					{
						m_flBulletSpeed -= m_flBulletSpeed * m_flEntryDensity / sv_bullet_speed_modifier.GetFloat();
						break;
					}
				}
				break;
			}
			else if(trace.startsolid)//exit solid
			{
#ifdef CLIENT_DLL
				//TODO: penetration surface impact stuff
#endif //CLIENT_DLL
				vecExitPosition = trace.fractionleftsolid * vecNewRay + m_vTraceStart;
				flPenetrationDistance = vecEntryPosition.DistTo(vecExitPosition);
				switch(iBulletStopSpeedCase)
				{
					case BUTTER_MODE:
					{
						//Do nothing to bullet speed
						break;
					}
					case ONE_HIT_MODE:
					{
						REMOVE_BULLET_AND_END(index);
					}
					default:
					{
						m_flBulletSpeed -= flPenetrationDistance * m_flEntryDensity / sv_bullet_speed_modifier.GetFloat();
						break;
					}
				}
			}
			else if(trace.fraction!=1.0f)//hit solid
			{
				vecEntryPosition = trace.endpos;
#ifdef GAME_DLL
				int soundEntChannel = ( m_nFlags&FIRE_BULLETS_TEMPORARY_DANGER_SOUND ) ? SOUNDENT_CHANNEL_BULLET_IMPACT : SOUNDENT_CHANNEL_UNSPECIFIED;

				CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, vecEntryPosition, 200, 0.5, m_hCaller, soundEntChannel );
#endif
				if(FStrEq(trace.surface.name,"tools/toolsblockbullets"))
				{
					REMOVE_BULLET_AND_END(index);
				}
#ifdef CLIENT_DLL
				CEffectData data;
				data.m_vStart = trace.startpos;
				data.m_vOrigin = trace.endpos;
				data.m_nDamageType = m_nDamageType;
				//Clientside ragdolls' locations cannot be determined by the server
				DispatchEffect( "RagdollImpact", data );
				//TODO: surface impact stuff
#endif //CLIENT_DLL
				m_flEntryDensity = physprops->GetSurfaceData(trace.surface.surfaceProps)->physics.density;
#ifdef GAME_DLL
				if(trace.DidHitNonWorldEntity())
				{
					if(m_pIgnoreList->ShouldHitEntity(trace.m_pEnt,MASK_SHOT))
					{
						m_pIgnoreList->AddEntityToIgnore(trace.m_pEnt);
						EntityImpact(trace.m_pEnt);
					}
				}
#endif
				if(iBulletStopSpeedCase==ONE_HIT_MODE)
				{
					REMOVE_BULLET_AND_END(index);
				}
			}
		}
		m_vTraceStart = trace.endpos + m_vecDirShooting;
	}while(trace.endpos!=m_vecOrigin&&m_flBulletSpeed>flBulletStopSpeed);


	if(m_flBulletSpeed<=flBulletStopSpeed)
	{
		REMOVE_BULLET_AND_END(index);
	}
}
#ifdef GAME_DLL
void CSimulatedBullet::EntityImpact(CBaseEntity *pHit)
{
	//TODO: entity impact stuff
	if ( GetAmmoDef()->Flags(m_iAmmoType) & AMMO_FORCE_DROP_IF_CARRIED )
	{
		// Make sure if the player is holding this, he drops it
		Pickup_ForcePlayerToDropThisObject( pHit );		
	}
}
#endif
#ifdef CLIENT_DLL
void CBulletManager::ClientThink(void)
#else
void CBulletManager::Think(void)
#endif
{
	for(int x=0;x<=m_pBullets.Count();x++)
	{
		m_pBullets[x]->SimulateBullet(x);
	}
#ifdef CLIENT_DLL
	ClientThinkList()->SetNextClientThink( GetClientHandle(), gpGlobals->curtime + 0.01f );
#else
	SetNextThink( gpGlobals->curtime + 0.01f );
#endif
}
void CBulletManager::AddBullet(CSimulatedBullet *pBullet)
{
	if (pBullet->AmmoIndex() == -1)
	{
		DevMsg("ERROR: Undefined ammo type!\n");
		return;
	}
	int index = m_pBullets.AddToTail(pBullet);
	DevMsg( "Bullet Created (%i) LagCompensation %f\n",index, pBullet->LagCompensation() );

	if(m_pBullets[index]->LagCompensation()!=0.0f)
		m_pBullets[index]->SimulateBullet(index, pBullet->LagCompensation());
}
void CBulletManager::RemoveBullet(int index)
{
	m_pBullets.Remove(index);
}

hl2mp_gamerules.cpp

Change GetAmmoDef to the following:

CAmmoDef *GetAmmoDef()
{
	static CAmmoDef def;
	static bool bInitted = false;
	
	if ( !bInitted )
	{
		bInitted = true;
		//		Name		Damage				Tracer			PlrDmg	NPCDmg	MaxCarry	ft/sec	Physics Force Impulse		Flags
		def.AddAmmoType("AR2",		DMG_BULLET,			TRACER_LINE_AND_WHIZ,	0,	0,	60,		1225,	BULLET_IMPULSE(200, 1225),	0 );
		def.AddAmmoType("AR2AltFire",	DMG_DISSOLVE,			TRACER_NONE,		0,	0,	3,		0,	0,				0 );
		def.AddAmmoType("Pistol",	DMG_BULLET,			TRACER_LINE_AND_WHIZ,	0,	0,	150,		1225,	BULLET_IMPULSE(200, 1225),	0 );
		def.AddAmmoType("SMG1",		DMG_BULLET,			TRACER_LINE_AND_WHIZ,	0,	0,	225,		1225,	BULLET_IMPULSE(200, 1225),	0 );
		def.AddAmmoType("357",		DMG_BULLET,			TRACER_LINE_AND_WHIZ,	0,	0,	12,		5000,	BULLET_IMPULSE(800, 5000),	0 );
		def.AddAmmoType("XBowBolt",	DMG_BULLET,			TRACER_LINE,		0,	0,	10,		8000,	BULLET_IMPULSE(800, 8000),	0 );
		def.AddAmmoType("Buckshot",	DMG_BULLET | DMG_BUCKSHOT,	TRACER_LINE,		0,	0,	30,		1200,	BULLET_IMPULSE(400, 1200),	0 );
		def.AddAmmoType("RPG_Round",	DMG_BURN,			TRACER_NONE,		0,	0,	3,		0,	0,				0 );
		def.AddAmmoType("SMG1_Grenade",	DMG_BURN,			TRACER_NONE,		0,	0,	3,		0,	0,				0 );
		def.AddAmmoType("Grenade",	DMG_BURN,			TRACER_NONE,		0,	0,	5,		0,	0,				0 );
		def.AddAmmoType("slam",		DMG_BURN,			TRACER_NONE,		0,	0,	5,		0,	0,				0 );
	}

	return &def;
}

As you can see, the bullet speed is derived from the second argument of the bullet impulses.

ammodef.h

Change the Ammo_t structure to the following:

struct Ammo_t 
{
	char 					*pName;
	int					nDamageType;
	int					eTracerType;
	float					physicsForceImpulse;
	float					flFeetPerSecond;
	int					nMinSplashSize;
	int					nMaxSplashSize;

	int					nFlags;

	// Values for player/NPC damage and carrying capability
	// If the integers are set, they override the CVars
	int					pPlrDmg;		// CVar for player damage amount
	int					pNPCDmg;		// CVar for NPC damage amount
	int					pMaxCarry;		// CVar for maximum number can carry
	const ConVar*				pPlrDmgCVar;		// CVar for player damage amount
	const ConVar*				pNPCDmgCVar;		// CVar for NPC damage amount
	const ConVar*				pMaxCarryCVar;		// CVar for maximum number can carry
};

Change the first two AddAmmoType function prototypes to the following:

	void				AddAmmoType(char const* name, int damageType, int tracerType,
							int plr_dmg, int npc_dmg, int carry,
							float ftpersec, float physicsForceImpulse,
							int nFlags, int minSplashSize = 4,
							int maxSplashSize = 8 );

	void				AddAmmoType(char const* name, int damageType, int tracerType,
							char const* plr_cvar, char const* npc_var,
							char const* carry_cvar, float ftpersec,
							float physicsForceImpulse, int nFlags,
							int minSplashSize = 4, int maxSplashSize = 8 );

ammodef.cpp

Add
float ftpersec,
Before both
float physicsForceImpulse,

Add
m_AmmoType[m_nAmmoIndex].flFeetPerSecond = ftpersec;
After both
m_AmmoType[m_nAmmoIndex].physicsForceImpulse = physicsForceImpulse;

Implementation

bullet_manager entity

gamerules.cpp

Add
#include "bullet_manager.h"
After
#include "filesystem.h"

Add
g_pBulletManager = (CBulletManager*)CBaseEntity::Create( "bullet_manager", vec3_origin, vec3_angle );
After
g_pPlayerResource = (CPlayerResource*)CBaseEntity::Create( "player_manager", vec3_origin, vec3_angle );

Making weapons shoot them