Dual Pistols (CSS Style): Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
m (Added "-")
 
(16 intermediate revisions by 4 users not shown)
Line 3: Line 3:


== Getting Started ==
== Getting Started ==
Firstly, you will need to make a copy of the file "weapon_pistol.cpp", renaming the copy to "weapon_dualies.cpp". You can find the file in either the "src\game\shared\hl2mp" directory (for multiplayer) or <sp directory here> (for singleplayer).
Firstly, you will need to make a copy of the file "weapon_pistol.cpp", renaming the copy to "weapon_dualies.cpp". You can find the file in either the <src\game_shared\hl2mp> directory (for 2006 multiplayer), <src\game\shared\hl2mp> (for 2007 multiplayer) or <src\game\server\hl2> (for singleplayer).


:'''Note:''' Feel free to name your dual pistols something else ("dualies" is just an example).
{{note| Feel free to name your dual pistols something else ("dualies" is just an example).}}




Now open the newly created file in your IDE of choice and do a search for the word "Pistol", replacing all instances with "Dualies" instead. Unfortunately, there is one part of the code we didn't actually want changed in this way - so find the section that looks similar to what's shown below and change all instances of the word "Dualies" back to "PISTOL".
Now open the newly created file in your IDE of choice and do a search for the word "Pistol", replacing all instances with "Dualies" instead. Unfortunately, there is one part of the code we didn't actually want changed in this way - so find the section that looks like the snippet below and change all instances of the word "Dualies" back to "PISTOL" (as shown).
 
:'''Note:''' The below is a representation of multiplayer code. Singleplayer modders can still make use of it - they just can't copy and paste it directly into their work.


<source lang=cpp>#ifndef CLIENT_DLL
<source lang=cpp>#ifndef CLIENT_DLL
Line 24: Line 22:
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, false },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, false },
};</source>
};</source>
{{note| The above is a representation of multiplayer code. Singleplayer modders can still make use of it - they just can't copy and paste it directly into their work.}}




:'''Note:''' One further thing to make sure of is that you include "weapon_dualies.cpp" in both the client and server projects of your solution. For multiplayer, the correct location is "Client HL2MP\Source Files\HL2MP\Weapons" (replacing "Client" with "Server" for the server project location). For singleplayer, the correction location is <sp directory here>.
One further thing to make sure of when modding multiplayer is that you include "weapon_dualies.cpp" in both the client and server projects of your solution. The correct location is <Client HL2MP\Source Files\HL2MP\Weapons> (replacing "Client" with "Server" for the server project location).


== The Stub and the Flip ==
== The Stub and the Flip ==


So, as I said, we need to add it as a stub. So now, go to '''"c_weapon__stubs_hl2.cpp"''' and add:
Now we need to add it as a stub. So now, go to '''"c_weapon__stubs_hl2.cpp"''' in the Client project and add:
<source lang=cpp>STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );</source>
<source lang=cpp>STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );</source>
Where the pistol is located.  
Where the pistol is located.  
Line 39: Line 39:
Now we must code 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"'''
Add this method after '''CWeaponDualies::PrimaryAttack()''':
<source lang=cpp>
<source lang=cpp>
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Dualies Firing
// Purpose: Dualies Firing
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::RightDualiesAttack()
void CWeaponDualies::LeftGunAttack()
{
{
// If my clip is empty (and I use clips) start reload
// If my clip is empty (and I use clips) start reload
Line 125: Line 125:
}</source>
}</source>


Since that's done, go back to '''"weapon_dualies.cpp"''' and go down to:
After that is done, go down to:
<source lang=cpp>class CWeaponDualies : public CBaseHL2MPCombatWeapon</source>
<source lang=cpp>class CWeaponDualies : public CBaseHL2MPCombatWeapon</source>
and find:
and find:
<source lang=cpp>
void Precache();
void ItemPostFrame();
void ItemPreFrame();
void ItemBusyFrame();
void PrimaryAttack();
void AddViewKick();
void DryFire();
</source>
and change that to:
<source lang=cpp>
void Precache();
void ItemPostFrame();
void ItemPreFrame();
void ItemBusyFrame();
void PrimaryAttack();
void AddViewKick();
void DryFire();
void PostFireStuff();
</source>
then go to:


<source lang=cpp>
<source lang=cpp>
Line 170: Line 146:
CNetworkVar( int, m_nNumShotsFired );
CNetworkVar( int, m_nNumShotsFired );


bool Flip;
bool bFlip;
</source>
</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'''
{{note| in the singleplayer source code the four vars that are already present are not networked.}}
 
Scroll down until you reach
 
<source lang=cpp>        // Weapon firing
virtual void PrimaryAttack(); // do "+ATTACK"
virtual void SecondaryAttack() { return; } // do "+ATTACK2"</source>


And change that to
Now we need to define our new LeftGunAttack method in the class definition:


<source lang=cpp>       // Weapon firing
Under
virtual void PrimaryAttack(); // do "+ATTACK"
<source lang=cpp>void PrimaryAttack( void );</source>
virtual void RightDualiesAttack(); // do right gun shot"
add:
virtual void SecondaryAttack() { return; } // do "+ATTACK2"</source>
<source lang=cpp>void LeftGunAttack( void );</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:
<source lang=cpp>void CWeaponDualies::PrimaryAttack()</source>
<source lang=cpp>void CWeaponDualies::PrimaryAttack()</source>
And make the function look like this:
And make the method look like this:
<source lang=cpp>void CWeaponDualies::PrimaryAttack()
<source lang=cpp>void CWeaponDualies::PrimaryAttack()
{
{
Line 206: Line 176:


//Flipping Code -Jman
//Flipping Code -Jman
if ( Flip == true )
if ( !bFlip)
{
{
BaseClass::PrimaryAttack();
BaseClass::PrimaryAttack();
Flip = false;
bFlip= true;
PostFireStuff();
}
}
else
else
{
{
BaseClass::RightDualiesAttack();
LeftGunAttack();
Flip = true;
bFlip= false;
PostFireStuff();
}
}
}
}
</source>


//Post Fire things.
== Weapon View Model and World Model ==
void CWeaponDualies::PostFireStuff()
If you were to play your mod right now, and give yourself dual pistols, then it would just be a single pistol, but fire as two. To fix this, we must use new models. There may be a way to make it so there are dual HL2 pistols, and two view models, but this way is much, much easier. First go into Steam/Steamapps/Sourcemods/*Mod Name Here*/. Make a new folder called models. Make a new folder in models called weapons. Now, you have a few choices here. If you own Counter-Strike: Source, then you can just extract the Elite models. You can also just download a skin from FPS Banana. If you download one from FPS Banana then you should get permission from the author and include him in the credits of your readme file. You can also make new models. Just make sure that all of the files are in models/weapons.
{
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
Now, you will probably see that the hands are texture-less (purple and black checkerboard). The way to fix this is to get a hand model from Counter-Strike: Source. Again, you can download from FPS Banana, extract them from your CS:S directory, or make your own. Either way, you need a hands folder, with the hand materials in them. To make them work in-game, go to your mod folder in Steam/Steamapps/Sourcemods/*YOUR MOD NAME*. Make a new folder called materials. In that make a new folder called models. In that make a new folder called weapons. In '''that''' make a new folder called v_models. Extract the hands directory here.
m_flAccuracyPenalty += DUALIES_ACCURACY_SHOT_PENALTY_TIME;
}</source>


== Weapon Script File ==
== Weapon Script File ==


Now that the coding is complete, a script file for the new weapon needs to be created (see [[weapon script|here]] for more information).
Now that the coding is complete, a script file for the new weapon needs to be created (see [[weapon script|here]] for more on weapon script files).


The easy way to do this is to make a copy of the file "weapon_pistol.txt", renaming the copy to "weapon_dualies.txt" (sound familiar?). You can find the file in the "Steam\steamapps\SourceMods\<yourmod>\scripts" directory.
The easy way to do this is to make a copy of the file "weapon_pistol.txt", renaming the copy to "weapon_dualies.txt" (sound familiar?). You can find the file in the "Steam\steamapps\SourceMods\<yourmod>\scripts" directory. Set the View model to "models/weapons/v_pist_elite.mdl" (whatever the model name is, and make sure you include the quotes!)
and set the player model to "models/weapons/w_pist_elite.mdl" (again, whatever the model name is and include the quotes).


Now open the newly created file in your text editor of choice and make the appropriate modifications to set a new bucket position, apply new models, etc..


== Conclusion ==
== Conclusion ==


Now when you next play your mod you should have a working pair of dual pistols!
Now when you next play your mod you should have a working pair of dual pistols! However, the next logical step would be making it so that the left mouse controls the left gun, and the right button controls the right gun.


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

Latest revision as of 12:16, 27 April 2021

Broom icon.png
This article or section needs to be cleaned up to conform to a higher standard of quality.
For help, see the VDC Editing Help and Wikipedia cleanup process. Also, remember to check for any notes left by the tagger at this article's talk page.

This article will explain how to implement dual pistols in both singleplayer and multiplayer Half-Life 2 mods (using Counter-Strike: Source as a basis).

Getting Started

Firstly, you will need to make a copy of the file "weapon_pistol.cpp", renaming the copy to "weapon_dualies.cpp". You can find the file in either the <src\game_shared\hl2mp> directory (for 2006 multiplayer), <src\game\shared\hl2mp> (for 2007 multiplayer) or <src\game\server\hl2> (for singleplayer).

Note.pngNote: Feel free to name your dual pistols something else ("dualies" is just an example).


Now open the newly created file in your IDE of choice and do a search for the word "Pistol", replacing all instances with "Dualies" instead. Unfortunately, there is one part of the code we didn't actually want changed in this way - so find the section that looks like the snippet below and change all instances of the word "Dualies" back to "PISTOL" (as shown).

#ifndef CLIENT_DLL
acttable_t CWeaponDualies::m_acttable[] = 
{
	{ ACT_HL2MP_IDLE,			ACT_HL2MP_IDLE_PISTOL,				false },
	{ ACT_HL2MP_RUN,			ACT_HL2MP_RUN_PISTOL,				false },
	{ ACT_HL2MP_IDLE_CROUCH,		ACT_HL2MP_IDLE_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_WALK_CROUCH,		ACT_HL2MP_WALK_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,		false },
	{ ACT_HL2MP_GESTURE_RELOAD,		ACT_HL2MP_GESTURE_RELOAD_PISTOL,		false },
	{ ACT_HL2MP_JUMP,			ACT_HL2MP_JUMP_PISTOL,				false },
	{ ACT_RANGE_ATTACK1,			ACT_RANGE_ATTACK_PISTOL,			false },
};
Note.pngNote: The above is a representation of multiplayer code. Singleplayer modders can still make use of it - they just can't copy and paste it directly into their work.


One further thing to make sure of when modding multiplayer is that you include "weapon_dualies.cpp" in both the client and server projects of your solution. The correct location is <Client HL2MP\Source Files\HL2MP\Weapons> (replacing "Client" with "Server" for the server project location).

The Stub and the Flip

Now we need to add it as a stub. So now, go to "c_weapon__stubs_hl2.cpp" in the Client project and add:

STUB_WEAPON_CLASS( weapon_dualies, WeaponDualies, C_BaseHLCombatWeapon );

Where the pistol is located.

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


Now we must code the flip.

Add this method after CWeaponDualies::PrimaryAttack():

//-----------------------------------------------------------------------------
// Purpose: Dualies Firing
//-----------------------------------------------------------------------------
void CWeaponDualies::LeftGunAttack()
{
	// 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();
}

After that is done, go down to:

class CWeaponDualies : public CBaseHL2MPCombatWeapon

and find:

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 bFlip;
Note.pngNote: in the singleplayer source code the four vars that are already present are not networked.

Now we need to define our new LeftGunAttack method in the class definition:

Under

void	PrimaryAttack( void );

add:

void	LeftGunAttack( void );

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

void CWeaponDualies::PrimaryAttack()

And make the method 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 ( !bFlip)
	{
		BaseClass::PrimaryAttack();
		bFlip= true;
	}
	else
	{
		LeftGunAttack();
		bFlip= false;
	}
}

Weapon View Model and World Model

If you were to play your mod right now, and give yourself dual pistols, then it would just be a single pistol, but fire as two. To fix this, we must use new models. There may be a way to make it so there are dual HL2 pistols, and two view models, but this way is much, much easier. First go into Steam/Steamapps/Sourcemods/*Mod Name Here*/. Make a new folder called models. Make a new folder in models called weapons. Now, you have a few choices here. If you own Counter-Strike: Source, then you can just extract the Elite models. You can also just download a skin from FPS Banana. If you download one from FPS Banana then you should get permission from the author and include him in the credits of your readme file. You can also make new models. Just make sure that all of the files are in models/weapons.

Now, you will probably see that the hands are texture-less (purple and black checkerboard). The way to fix this is to get a hand model from Counter-Strike: Source. Again, you can download from FPS Banana, extract them from your CS:S directory, or make your own. Either way, you need a hands folder, with the hand materials in them. To make them work in-game, go to your mod folder in Steam/Steamapps/Sourcemods/*YOUR MOD NAME*. Make a new folder called materials. In that make a new folder called models. In that make a new folder called weapons. In that make a new folder called v_models. Extract the hands directory here.

Weapon Script File

Now that the coding is complete, a script file for the new weapon needs to be created (see here for more on weapon script files).

The easy way to do this is to make a copy of the file "weapon_pistol.txt", renaming the copy to "weapon_dualies.txt" (sound familiar?). You can find the file in the "Steam\steamapps\SourceMods\<yourmod>\scripts" directory. Set the View model to "models/weapons/v_pist_elite.mdl" (whatever the model name is, and make sure you include the quotes!) and set the player model to "models/weapons/w_pist_elite.mdl" (again, whatever the model name is and include the quotes).


Conclusion

Now when you next play your mod you should have a working pair of dual pistols! However, the next logical step would be making it so that the left mouse controls the left gun, and the right button controls the right gun.