Dual Pistols (CSS Style): Difference between revisions
TomEdwards (talk | contribs) (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: | ||
< | <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 }, | ||
};</ | };</source> | ||
'''With:''' | '''With:''' | ||
< | <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 }, | ||
};</ | };</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: | ||
< | <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"''' | ||
< | <source lang=cpp> | ||
//----------------------------------------------------------------------------- | |||
// Purpose: Dualies Firing | // Purpose: Dualies Firing | ||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||
void CBaseCombatWeapon::RightDualiesAttack( | 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(); | ||
}</ | }</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: | ||
< | <source lang=cpp>class CWeaponDualies : public CBaseHL2MPCombatWeapon</source> | ||
and find: | and find: | ||
< | <source lang=cpp> | ||
void ItemPostFrame( | void Precache(); | ||
void ItemPreFrame( | void ItemPostFrame(); | ||
void ItemBusyFrame( | void ItemPreFrame(); | ||
void PrimaryAttack( | void ItemBusyFrame(); | ||
void AddViewKick( | void PrimaryAttack(); | ||
void DryFire( | void AddViewKick(); | ||
void DryFire(); | |||
</source> | |||
and change that to: | and change that to: | ||
< | |||
void ItemPostFrame( | <source lang=cpp> | ||
void ItemPreFrame( | void Precache(); | ||
void ItemBusyFrame( | void ItemPostFrame(); | ||
void PrimaryAttack( | void ItemPreFrame(); | ||
void AddViewKick( | void ItemBusyFrame(); | ||
void DryFire( | void PrimaryAttack(); | ||
void PostFireStuff( | void AddViewKick(); | ||
void DryFire(); | |||
void PostFireStuff(); | |||
</source> | |||
then go to: | then go to: | ||
< | |||
<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 );</ | CNetworkVar( int, m_nNumShotsFired ); | ||
</source> | |||
and change that to: | and change that to: | ||
< | |||
<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;</ | 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 | ||
< | <source lang=cpp> // Weapon firing | ||
virtual void PrimaryAttack( | virtual void PrimaryAttack(); // do "+ATTACK" | ||
virtual void SecondaryAttack( | virtual void SecondaryAttack() { return; } // do "+ATTACK2"</source> | ||
And change that to | And change that to | ||
< | <source lang=cpp> // Weapon firing | ||
virtual void PrimaryAttack( | virtual void PrimaryAttack(); // do "+ATTACK" | ||
virtual void RightDualiesAttack( | virtual void RightDualiesAttack(); // do right gun shot" | ||
virtual void SecondaryAttack( | 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: | ||
< | <source lang=cpp>void CWeaponDualies::PrimaryAttack()</source> | ||
And make the function look like this: | And make the function look like this: | ||
< | <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 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; | ||
}</ | }</source> | ||
== The text script == | == The text script == | ||
Line 236: | Line 250: | ||
[[Category:Tutorials]] | [[Category:Tutorials]] | ||
[[Category: | [[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.