Dual Pistols (CSS Style): Difference between revisions
| m (categorized) | |||
| Line 24: | Line 24: | ||
| acttable_t CWeaponDualies::m_acttable[] =   | acttable_t CWeaponDualies::m_acttable[] =   | ||
| { | { | ||
| 	{ ACT_HL2MP_IDLE,	 | 	{ ACT_HL2MP_IDLE,			ACT_HL2MP_IDLE_PISTOL,				false }, | ||
| 	{ ACT_HL2MP_RUN,	 | 	{ ACT_HL2MP_RUN,			ACT_HL2MP_RUN_PISTOL,				false }, | ||
| 	{ ACT_HL2MP_IDLE_CROUCH,	 | 	{ ACT_HL2MP_IDLE_CROUCH,		ACT_HL2MP_IDLE_CROUCH_PISTOL,			false }, | ||
| 	{ ACT_HL2MP_WALK_CROUCH,	 | 	{ 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_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,		false }, | ||
| 	{ ACT_HL2MP_GESTURE_RELOAD,	 | 	{ ACT_HL2MP_GESTURE_RELOAD,		ACT_HL2MP_GESTURE_RELOAD_PISTOL,		false }, | ||
| 	{ ACT_HL2MP_JUMP,	 | 	{ ACT_HL2MP_JUMP,			ACT_HL2MP_JUMP_PISTOL,				false }, | ||
| 	{ ACT_RANGE_ATTACK1,	 | 	{ ACT_RANGE_ATTACK1,			ACT_RANGE_ATTACK_PISTOL,			false }, | ||
| };</pre> | };</pre> | ||
Revision as of 13:09, 12 November 2008
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_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 },
};
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( void )
{
	// 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 ); void ItemPostFrame( void ); void ItemPreFrame( void ); void ItemBusyFrame( void ); void PrimaryAttack( void ); void AddViewKick( void ); void DryFire( void );
and change that to:
void Precache( void ); void ItemPostFrame( void ); void ItemPreFrame( void ); void ItemBusyFrame( void ); void PrimaryAttack( void ); void AddViewKick( void ); void DryFire( void ); void PostFireStuff( void );
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( void );						// do "+ATTACK"
	virtual void			SecondaryAttack( void ) { return; }			// do "+ATTACK2"
And change that to
        // Weapon firing
	virtual void			PrimaryAttack( void );						// do "+ATTACK"
	virtual void			RightDualiesAttack( void );						// do right gun shot"
	virtual void			SecondaryAttack( void ) { return; }			// do "+ATTACK2"
Now you have everything pretty well set up. Finally, go down to:
void CWeaponDualies::PrimaryAttack( void )
And make the function look like this:
void CWeaponDualies::PrimaryAttack( void )
{
	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( void )
{
	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.