Semi or Burst fire: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(removed first person)
No edit summary
Line 1: Line 1:
This is a simple tutorial about adding semi-auto or burst fire mode to a weapon. we will use the '''weapon_pistol.cpp''' as the basis of the tutorial. Look up this part at the declaration of the pistol class. The extra lines are bold.
Hi
 
This is a simple tutorial about adding semi-auto or burst fire mode to a weapon. I will use the '''weapon_pistol.cpp''' as the basis of the tutorial. The extra lines are bold.
 
First define a constant. That holds the maximum number of bullets to be fired with 1 trigger pull. In semi-auto, you would add 1. For a 3 shot burst add 3 etc.
#define PISTOL_ACCURACY_SHOT_PENALTY_TIME 0.2f // Applied amount of time each shot adds to the time we must recover from
#define PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME 1.5f // Maximum penalty to deal out
'''#define MAXBURST 1'''
 
 
Now look up this part in the code at the declaration of the pistol class. Then add the bold lines.  


  private:
  private:
Line 35: Line 46:
  END_PREDICTION_DATA()
  END_PREDICTION_DATA()


This created the m_iSemi variable. The exact purpose of the code above is not currently clear (please amend this if you can). It has something to do with client side prediction, to ease the server load. The important part is that it works!
This created the m_iSemi variable. However I don't know the exact purpose of the code above. It has something to do with client side prediction, to ease the server load. The important part is that it works :).


Now define a constant. That holds the maximum number of bullets to be fired with 1 trigger pull. In semi-auto, you would add 1. For a 3 shot burst add 3 etc.
Now set up our new variable in the constructor:
   
   
  #define PISTOL_ACCURACY_SHOT_PENALTY_TIME 0.2f // Applied amount of time each shot adds to the time we must recover from
  CWeaponPistol::CWeaponPistol( void )
#define PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME 1.5f // Maximum penalty to deal out
{
  '''#define MAXBURST 1'''
m_flSoonestPrimaryAttack = gpGlobals->curtime;
m_flAccuracyPenalty = 0.0f;
m_fMinRange1 = 24;
m_fMaxRange1 = 1500;
m_fMinRange2 = 24;
m_fMaxRange2 = 200;
m_bFiresUnderwater = true;
'''m_iSemi=MAXBURST;'''
}
 
Here comes the tricky part. Look up the ''ItemPostFrame'' procedure and add these lines:
'''CBasePlayer *pOwner = ToBasePlayer( GetOwner() );'''
'''if ( pOwner->m_nButtons & IN_ATTACK  ){}else '''
'''{m_iSemi = MAXBURST;} '''
 
This sets the m_iSemi variable to our the pre-defined constant if the player does not push the primary fire button. I know that the logic check is kinda funny with only the ELSE part having code. This works, but feel free to make it more elegant.
To finish up the modification, add the bold lines into the ''PrimaryAttack'' procedure:
'''if (m_iSemi<=0)'''
'''{ return; }'''
'''m_iSemi--;'''
BaseClass::PrimaryAttack();
 
Now this will deduct each shot fired from the allowed shots as long as you push the button. If you fired more then the definded value, the gun will cease to fire. You need to release the trigger and push it again for an other shot/burst.
12 lines alltogether. To make a gun selective fire you would need to set up an extra bool variable (like m_bSemi) and trigger it with something (like 2nd fire). Then replace the '''m_iSemi--;''' line with this '''if ( m_bSemi ) {m_iSemi--;}'''.

Revision as of 13:58, 25 July 2006

Hi

This is a simple tutorial about adding semi-auto or burst fire mode to a weapon. I will use the weapon_pistol.cpp as the basis of the tutorial. The extra lines are bold.

First define a constant. That holds the maximum number of bullets to be fired with 1 trigger pull. In semi-auto, you would add 1. For a 3 shot burst add 3 etc.

#define	PISTOL_ACCURACY_SHOT_PENALTY_TIME		0.2f	// Applied amount of time each shot adds to the time we must recover from
#define	PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME	1.5f	// Maximum penalty to deal out
#define	MAXBURST	1


Now look up this part in the code at the declaration of the pistol class. Then add the bold lines.

private:
CNetworkVar( float,	m_flSoonestPrimaryAttack );
CNetworkVar( float,	m_flLastAttackTime );
CNetworkVar( float,	m_flAccuracyPenalty );
CNetworkVar( int,	m_nNumShotsFired );
CNetworkVar( int,	m_iSemi );


private:
CWeaponPistol( const CWeaponPistol & );
};
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPistol, DT_WeaponPistol )

BEGIN_NETWORK_TABLE( CWeaponPistol, DT_WeaponPistol )
#ifdef CLIENT_DLL
RecvPropTime( RECVINFO( m_flSoonestPrimaryAttack ) ),
RecvPropTime( RECVINFO( m_flLastAttackTime ) ),
RecvPropFloat( RECVINFO( m_flAccuracyPenalty ) ),
RecvPropInt( RECVINFO( m_nNumShotsFired ) ),
RecvPropInt( RECVINFO( m_iSemi ) ),
#else
SendPropTime( SENDINFO( m_flSoonestPrimaryAttack ) ),
SendPropTime( SENDINFO( m_flLastAttackTime ) ),
SendPropFloat( SENDINFO( m_flAccuracyPenalty ) ),
SendPropInt( SENDINFO( m_nNumShotsFired ) ),
SendPropInt( SENDINFO( m_iSemi ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponPistol )
DEFINE_PRED_FIELD( m_iSemi, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()

This created the m_iSemi variable. However I don't know the exact purpose of the code above. It has something to do with client side prediction, to ease the server load. The important part is that it works :).

Now set up our new variable in the constructor:

CWeaponPistol::CWeaponPistol( void )
{
m_flSoonestPrimaryAttack = gpGlobals->curtime;
m_flAccuracyPenalty = 0.0f;
m_fMinRange1		= 24;
m_fMaxRange1		= 1500;
m_fMinRange2		= 24;
m_fMaxRange2		= 200;
m_bFiresUnderwater	= true;
m_iSemi=MAXBURST; 
}

Here comes the tricky part. Look up the ItemPostFrame procedure and add these lines:

CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner->m_nButtons & IN_ATTACK  ){}else 
{m_iSemi = MAXBURST;} 

This sets the m_iSemi variable to our the pre-defined constant if the player does not push the primary fire button. I know that the logic check is kinda funny with only the ELSE part having code. This works, but feel free to make it more elegant. To finish up the modification, add the bold lines into the PrimaryAttack procedure:

if (m_iSemi<=0)
{ return;	}
m_iSemi--;
BaseClass::PrimaryAttack();

Now this will deduct each shot fired from the allowed shots as long as you push the button. If you fired more then the definded value, the gun will cease to fire. You need to release the trigger and push it again for an other shot/burst. 12 lines alltogether. To make a gun selective fire you would need to set up an extra bool variable (like m_bSemi) and trigger it with something (like 2nd fire). Then replace the m_iSemi--; line with this if ( m_bSemi ) {m_iSemi--;}.