Burst Fire (Machine Gun)

From Valve Developer Community
Jump to: navigation, search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024

The code below will add a burst mode functionality to any machine gun based weapon for the its secondary fire. It has only been tested using the HL2MP OB version of Source SDK's source code, though with a few modifications, it should work with most any version available.

The code calls for the sound "BURST", which must be defined in your weapon's .txt file in your /scripts folder. If it is not, no sound will play when you burst fire the weapon, so make sure it is added before you continue. Also, remember to replace any references to "CWeaponSMG1" with the unique class name of the weapon whose secondary fire you wish to replace. If you find that you're getting errors or warnings upon compiling after following the instructions below, chances are some more changes are needed. You will need to diagnose any issues yourself, I'm afraid, though for the most part everything below should work.

The code

If the weapon you are modifying does not have a SecondaryAttack() function yet, declare it in the weapon's class before continuing by adding the following under one of your "public:" entries in your weapon's class:

void SecondaryAttack( void );

If your declaration of the SecondaryAttack() function does not look exactly like this, replace it with the above just in case.

Conversely, if you find that you already have a declaration and a similar function, be sure to replace the entire function with the code below.

Here's what's going on below that's worth noting before you go on copying and pasting:

  • Force a 0.5 second delay in between firing.
  • Ensure the weapon is only firing three bullets at most.
void CWeaponSMG1::SecondaryAttack( void )
{
	// Check our secondary attack delay before anything
	if ( m_flNextSecondaryAttack > gpGlobals->curtime )
		return;

	// Only the player fires this way so we can cast
	CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
	if ( !pPlayer )
		return;
	
	// Abort here to handle burst and auto fire modes
	if ( (UsesClipsForAmmo1() && m_iClip1 == 0) || ( !UsesClipsForAmmo1() && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType) ) )
		return;

	m_nShotsFired++;

	pPlayer->DoMuzzleFlash();

	// To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems, 
	// especially if the weapon we're firing has a really fast rate of fire.
	int iBulletsToFire = 0;
	float fireRate = GetFireRate();

	while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
	{
		// MUST call sound before removing a round from the clip of a CHLMachineGun
		WeaponSound(BURST, m_flNextPrimaryAttack);
		m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
		iBulletsToFire++;
	}

	// Make sure we don't fire more than the amount in the clip, if this weapon uses clips
	if ( UsesClipsForAmmo1() )
	{
		if ( iBulletsToFire > 3 )
			iBulletsToFire = 3;

		if ( iBulletsToFire > m_iClip1 )
			iBulletsToFire = m_iClip1;

		m_iClip1 -= iBulletsToFire;
	}

	CHL2MP_Player *pHL2MPPlayer = ToHL2MPPlayer( pPlayer );

	// Fire the bullets
	FireBulletsInfo_t info;
	info.m_iShots = iBulletsToFire;
	info.m_vecSrc = pHL2MPPlayer->Weapon_ShootPosition( );
	info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
	info.m_vecSpread = pHL2MPPlayer->GetAttackSpread( this );
	info.m_flDistance = MAX_TRACE_LENGTH;
	info.m_iAmmoType = m_iPrimaryAmmoType;
	info.m_iTracerFreq = 1;
	FireBullets( info );

	//Factor in the view kick
	AddViewKick();
	
	if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
	{
		// HEV suit - indicate out of ammo condition
		pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); 
	}

	SendWeaponAnim( GetPrimaryAttackActivity() );
	pPlayer->SetAnimation( PLAYER_ATTACK1 );

	m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
}