Dual Pistols (CSS Style)
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" and add a new function:
//----------------------------------------------------------------------------- // 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 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 CWeaponPistol::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 += PISTOL_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.