Dual Pistols (CSS Style): Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Category:Weapons programming, syntax highlight)
Line 1: Line 1:
This article will explain how to implement Counter-Strike Source style Dual Pistols into your Single or Multiplayer Half-Life 2 Mod.
This article will explain how to implement Counter-Strike Source style Dual Pistols into your Single or Multiplayer Half-Life 2 Mod.


== Getting started ==
== Getting started ==
Line 6: Line 5:


Right after that, rename the from '''"weapon_pistol"''' to '''"weapon_dualies"''' and open the file in whatever C++ program you are using. After this, press '''Ctrl+F''' and then Replace All instances of the word '''"Pistol"''' with the word '''"Dualies."''' After this, you should notice that this messed up your act table, so replace:
Right after that, rename the from '''"weapon_pistol"''' to '''"weapon_dualies"''' and open the file in whatever C++ program you are using. After this, press '''Ctrl+F''' and then Replace All instances of the word '''"Pistol"''' with the word '''"Dualies."''' After this, you should notice that this messed up your act table, so replace:
<pre>#ifndef CLIENT_DLL
<source lang=cpp>#ifndef CLIENT_DLL
acttable_t CWeaponDualies::m_acttable[] =  
acttable_t CWeaponDualies::m_acttable[] =  
{
{
Line 17: Line 16:
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_DUALIES, false },
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_DUALIES, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_DUALIES, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_DUALIES, false },
};</pre>
};</source>


'''With:'''
'''With:'''


<pre>#ifndef CLIENT_DLL
<source lang=cpp>#ifndef CLIENT_DLL
acttable_t CWeaponDualies::m_acttable[] =  
acttable_t CWeaponDualies::m_acttable[] =  
{
{
Line 32: Line 31:
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_DUALIES, false },
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_DUALIES, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_DUALIES, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_DUALIES, false },
};</pre>
};</source>


That should make the gun its own gun for now, but we still need to add it in the stubs file.
That should make the gun its own gun for now, but we still need to add it in the stubs file.
Line 39: Line 38:


So, as I said, we need to add it as a stub. So now, go to '''"c_weapon__stubs_hl2.cpp"''' and add:
So, as I said, we need to add it as a stub. So now, go to '''"c_weapon__stubs_hl2.cpp"''' and add:
<pre>STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );</pre>
<source lang=cpp>STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );</source>
Where the pistol is located.  
Where the pistol is located.  


Line 51: Line 50:


Go into '''"basecombatweapon_shared.cpp"''' which is in '''"game_shared"''' and add this new function after '''"CBaseCombatWeapon::PrimaryAttack"'''
Go into '''"basecombatweapon_shared.cpp"''' which is in '''"game_shared"''' and add this new function after '''"CBaseCombatWeapon::PrimaryAttack"'''
<pre>//-----------------------------------------------------------------------------
<source lang=cpp>
//-----------------------------------------------------------------------------
// Purpose: Dualies Firing
// Purpose: Dualies Firing
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::RightDualiesAttack( void )
void CBaseCombatWeapon::RightDualiesAttack()
{
{
// If my clip is empty (and I use clips) start reload
// If my clip is empty (and I use clips) start reload
Line 133: Line 133:
//Add our view kick in
//Add our view kick in
AddViewKick();
AddViewKick();
}</pre>
}</source>


Since that's done, go back to '''"weapon_dualies.cpp"''' and go down to:
Since that's done, go back to '''"weapon_dualies.cpp"''' and go down to:
<pre>class CWeaponDualies : public CBaseHL2MPCombatWeapon</pre>
<source lang=cpp>class CWeaponDualies : public CBaseHL2MPCombatWeapon</source>
and find:
and find:
<pre> void Precache( void );
<source lang=cpp>
void ItemPostFrame( void );
void Precache();
void ItemPreFrame( void );
void ItemPostFrame();
void ItemBusyFrame( void );
void ItemPreFrame();
void PrimaryAttack( void );
void ItemBusyFrame();
void AddViewKick( void );
void PrimaryAttack();
void DryFire( void );</pre>
void AddViewKick();
void DryFire();
</source>
and change that to:
and change that to:
<pre> void Precache( void );
 
void ItemPostFrame( void );
<source lang=cpp>
void ItemPreFrame( void );
void Precache();
void ItemBusyFrame( void );
void ItemPostFrame();
void PrimaryAttack( void );
void ItemPreFrame();
void AddViewKick( void );
void ItemBusyFrame();
void DryFire( void );
void PrimaryAttack();
void PostFireStuff( void );</pre>
void AddViewKick();
void DryFire();
void PostFireStuff();
</source>
then go to:
then go to:
<pre>private:
 
<source lang=cpp>
private:
CNetworkVar( float, m_flSoonestPrimaryAttack );
CNetworkVar( float, m_flSoonestPrimaryAttack );
CNetworkVar( float, m_flLastAttackTime );
CNetworkVar( float, m_flLastAttackTime );
CNetworkVar( float, m_flAccuracyPenalty );
CNetworkVar( float, m_flAccuracyPenalty );
CNetworkVar( int, m_nNumShotsFired );</pre>
CNetworkVar( int, m_nNumShotsFired );
</source>
and change that to:
and change that to:
<pre>private:
 
<source lang=cpp>
private:
CNetworkVar( float, m_flSoonestPrimaryAttack );
CNetworkVar( float, m_flSoonestPrimaryAttack );
CNetworkVar( float, m_flLastAttackTime );
CNetworkVar( float, m_flLastAttackTime );
Line 167: Line 180:
CNetworkVar( int, m_nNumShotsFired );
CNetworkVar( int, m_nNumShotsFired );


bool Flip;</pre>
bool Flip;
</source>


Now we need to define our new RightDualiesAttack function in '''basecombatweapon_shared.h''', which in your source is located in: '''src\game_shared\basecombatweapon_shared.h'''
Now we need to define our new RightDualiesAttack function in '''basecombatweapon_shared.h''', which in your source is located in: '''src\game_shared\basecombatweapon_shared.h'''
Line 173: Line 187:
Scroll down until you reach
Scroll down until you reach


<pre>        // Weapon firing
<source lang=cpp>        // Weapon firing
virtual void PrimaryAttack( void ); // do "+ATTACK"
virtual void PrimaryAttack(); // do "+ATTACK"
virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2"</pre>
virtual void SecondaryAttack() { return; } // do "+ATTACK2"</source>


And change that to
And change that to


<pre>        // Weapon firing
<source lang=cpp>        // Weapon firing
virtual void PrimaryAttack( void ); // do "+ATTACK"
virtual void PrimaryAttack(); // do "+ATTACK"
virtual void RightDualiesAttack( void ); // do right gun shot"
virtual void RightDualiesAttack(); // do right gun shot"
virtual void SecondaryAttack( void ) { return; } // do "+ATTACK2"</pre>
virtual void SecondaryAttack() { return; } // do "+ATTACK2"</source>


Now you have everything pretty well set up. Finally, go down to:
Now you have everything pretty well set up. Finally, go down to:
<pre>void CWeaponDualies::PrimaryAttack( void )</pre>
<source lang=cpp>void CWeaponDualies::PrimaryAttack()</source>
And make the function look like this:
And make the function look like this:
<pre>void CWeaponDualies::PrimaryAttack( void )
<source lang=cpp>void CWeaponDualies::PrimaryAttack()
{
{
if ( ( gpGlobals->curtime - m_flLastAttackTime ) > 0.5f )
if ( ( gpGlobals->curtime - m_flLastAttackTime ) > 0.5f )
Line 217: Line 231:


//Post Fire things.
//Post Fire things.
void CWeaponDualies::PostFireStuff( void )
void CWeaponDualies::PostFireStuff()
{
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
Line 227: Line 241:
// Add an accuracy penalty which can move past our maximum penalty time if we're really spastic
// Add an accuracy penalty which can move past our maximum penalty time if we're really spastic
m_flAccuracyPenalty += DUALIES_ACCURACY_SHOT_PENALTY_TIME;
m_flAccuracyPenalty += DUALIES_ACCURACY_SHOT_PENALTY_TIME;
}</pre>
}</source>


== The text script ==
== The text script ==
Line 236: Line 250:


[[Category:Tutorials]]
[[Category:Tutorials]]
[[Category:Programming]]
[[Category:Weapons programming]]

Revision as of 09:35, 15 August 2009

This article will explain how to implement Counter-Strike Source style Dual Pistols into your Single or Multiplayer Half-Life 2 Mod.

Getting started

First off you should copy weapon_pistol.cpp from ("game_shared/hl2mp" - For Users Editing Multiplayer Source) or ("dlls/hl2_dll" - For Users Editing Singleplayer Source) and paste it in the ("game_shared/hl2mp" - For Users Editing Multiplayer Source) or ("dlls/hl2_dll" - For Users Editing Singleplayer Source) folder.

Right after that, rename the from "weapon_pistol" to "weapon_dualies" and open the file in whatever C++ program you are using. After this, press Ctrl+F and then Replace All instances of the word "Pistol" with the word "Dualies." After this, you should notice that this messed up your act table, so replace:

#ifndef CLIENT_DLL
acttable_t CWeaponDualies::m_acttable[] = 
{
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_DUALIES,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_DUALIES,					false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_DUALIES,			false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_DUALIES,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_DUALIES,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_DUALIES,		false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_DUALIES,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_DUALIES,				false },
};

With:

#ifndef CLIENT_DLL
acttable_t CWeaponDualies::m_acttable[] = 
{
	{ ACT_HL2MP_IDLE,			ACT_HL2MP_IDLE_DUALIES,				false },
	{ ACT_HL2MP_RUN,			ACT_HL2MP_RUN_DUALIES,				false },
	{ ACT_HL2MP_IDLE_CROUCH,		ACT_HL2MP_IDLE_CROUCH_DUALIES,			false },
	{ ACT_HL2MP_WALK_CROUCH,		ACT_HL2MP_WALK_CROUCH_DUALIES,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_DUALIES,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,		ACT_HL2MP_GESTURE_RELOAD_DUALIES,		false },
	{ ACT_HL2MP_JUMP,			ACT_HL2MP_JUMP_DUALIES,				false },
	{ ACT_RANGE_ATTACK1,			ACT_RANGE_ATTACK_DUALIES,			false },
};

That should make the gun its own gun for now, but we still need to add it in the stubs file.

Adding it as a stub

So, as I said, we need to add it as a stub. So now, go to "c_weapon__stubs_hl2.cpp" and add:

STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );

Where the pistol is located.

Now you just need to drag the "weapon_dualies.cpp" file into both the client and server solutions. Where in them? ("Source Files/hl2mp/Weapons")

Now the gun is its own gun and works in game.

Coding the flip

Now we must code the flip.

Go into "basecombatweapon_shared.cpp" which is in "game_shared" and add this new function after "CBaseCombatWeapon::PrimaryAttack"

//-----------------------------------------------------------------------------
// Purpose: Dualies Firing
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::RightDualiesAttack()
{
	// If my clip is empty (and I use clips) start reload
	if ( UsesClipsForAmmo1() && !m_iClip1 ) 
	{
		Reload();
		return;
	}

	// Only the player fires this way so we can cast
	CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

	if (!pPlayer)
	{
		return;
	}

	// MUST call sound before removing a round from the clip of a CMachineGun
	WeaponSound(SINGLE);

	pPlayer->DoMuzzleFlash();

	SendWeaponAnim( GetSecondaryAttackActivity() );

	// player "shoot" animation
	pPlayer->SetAnimation( PLAYER_ATTACK1 );

	FireBulletsInfo_t info;
	info.m_vecSrc	 = pPlayer->Weapon_ShootPosition( );
	
	info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );

	// 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.
	info.m_iShots = 0;
	float fireRate = GetFireRate();

	while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
	{
		m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
		info.m_iShots++;
		if ( !fireRate )
			break;
	}

	// Make sure we don't fire more than the amount in the clip
	if ( UsesClipsForAmmo1() )
	{
		info.m_iShots = min( info.m_iShots, m_iClip1 );
		m_iClip1 -= info.m_iShots;
	}
	else
	{
		info.m_iShots = min( info.m_iShots, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) );
		pPlayer->RemoveAmmo( info.m_iShots, m_iPrimaryAmmoType );
	}

	info.m_flDistance = MAX_TRACE_LENGTH;
	info.m_iAmmoType = m_iPrimaryAmmoType;
	info.m_iTracerFreq = 2;

#if !defined( CLIENT_DLL )
	// Fire the bullets
	info.m_vecSpread = pPlayer->GetAttackSpread( this );
#else
	//!!!HACKHACK - what does the client want this function for? 
	info.m_vecSpread = GetActiveWeapon()->GetBulletSpread();
#endif // CLIENT_DLL

	pPlayer->FireBullets( info );

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

	//Add our view kick in
	AddViewKick();
}

Since that's done, go back to "weapon_dualies.cpp" and go down to:

class CWeaponDualies : public CBaseHL2MPCombatWeapon

and find:

	void	Precache();
	void	ItemPostFrame();
	void	ItemPreFrame();
	void	ItemBusyFrame();
	void	PrimaryAttack();
	void	AddViewKick();
	void	DryFire();

and change that to:

	void	Precache();
	void	ItemPostFrame();
	void	ItemPreFrame();
	void	ItemBusyFrame();
	void	PrimaryAttack();
	void	AddViewKick();
	void	DryFire();
	void	PostFireStuff();

then go to:

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

and change that to:

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

	bool Flip;

Now we need to define our new RightDualiesAttack function in basecombatweapon_shared.h, which in your source is located in: src\game_shared\basecombatweapon_shared.h

Scroll down until you reach

        // Weapon firing
	virtual void			PrimaryAttack();						// do "+ATTACK"
	virtual void			SecondaryAttack() { return; }			// do "+ATTACK2"

And change that to

        // Weapon firing
	virtual void			PrimaryAttack();						// do "+ATTACK"
	virtual void			RightDualiesAttack();						// do right gun shot"
	virtual void			SecondaryAttack() { return; }			// do "+ATTACK2"

Now you have everything pretty well set up. Finally, go down to:

void CWeaponDualies::PrimaryAttack()

And make the function look like this:

void CWeaponDualies::PrimaryAttack()
{
	if ( ( gpGlobals->curtime - m_flLastAttackTime ) > 0.5f )
	{
		m_nNumShotsFired = 0;
	}
	else
	{
		m_nNumShotsFired++;
	}

	m_flLastAttackTime = gpGlobals->curtime;
	m_flSoonestPrimaryAttack = gpGlobals->curtime + DUALIES_FASTEST_REFIRE_TIME;

	//Flipping Code -Jman
	if ( Flip == true )
	{
		BaseClass::PrimaryAttack();
		Flip = false;
		PostFireStuff();
	}
	else
	{
		BaseClass::RightDualiesAttack();
		Flip = true;
		PostFireStuff();
	}
}

//Post Fire things.
void CWeaponDualies::PostFireStuff()
{
	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
	if( pOwner )
	{
		pOwner->ViewPunchReset();
	}

	// Add an accuracy penalty which can move past our maximum penalty time if we're really spastic
	m_flAccuracyPenalty += DUALIES_ACCURACY_SHOT_PENALTY_TIME;
}

The text script

Now that the code's all done, you just need a text script for it, so copy "weapon_pistol.txt" in "YourModName/scripts," paste it, and rename it "weapon_dualies.txt" Now just edit the file to have a new bucket position (Inventory Position) and get a Counter Strike Source dual pistols model with the hands texture and the such, put it in your mod, and edit "weapon_dualies.txt" to use that model's name as the viewmodel.

Now when you use the guns in game, you should have a gun that swaps left and right guns each shot.