Full Holster Sequence (HL2MP): Difference between revisions
m (→Overview) |
(Rewrite Template:Lang to Template:LanguageBar. This action was performed by a bot.) |
||
(7 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
{{LanguageBar|Full Holster Sequence (HL2MP)}} | |||
This tutorial provides insight on giving an active weapon time to play its holster animation before showing a newly chosen weapon in the Half-Life 2 Deathmatch SDK. A new game system is introduced to the code so the switch is predicted on the client (which would only be needed in multiplayer). The code also prevents itself from being active when a player is being equipped when spawning. | This tutorial provides insight on giving an active weapon time to play its holster animation before showing a newly chosen weapon in the Half-Life 2 Deathmatch SDK. A new game system is introduced to the code so the switch is predicted on the client (which would only be needed in multiplayer). The code also prevents itself from being active when a player is being equipped when spawning. | ||
{{note|Not all of the weapons have holster animations and need to be reworked to fully implement this concept.}} | {{note|Not all of the weapons have holster animations and need to be reworked to fully implement this concept.}} | ||
{{note|For single player you need miss step in '''hl2mp_player.cpp'''}} | |||
==c_basecombatcharacter.h== | |||
Add the following to the client combat character class: | |||
<source lang=cpp>friend class C_ShowWeapon; // This allows CShowWeapon to access whatever it needs to update for the character</source> | |||
==basecombatcharacter.h== | |||
Add the following to the server combat character class: | |||
<source lang=cpp>friend class CShowWeapon; // This allows CShowWeapon to access whatever it needs to update for the character</source> | |||
==player.h== | |||
Add the following to the player class: | Add the following to the player class: | ||
===hl2mp_player.cpp | <source lang=cpp>public: | ||
bool IsSpawning() { return m_bSpawning; } | |||
protected: | |||
bool m_bSpawning;</source> | |||
==hl2mp_player.cpp== | |||
Add the following before the calls to GiveNamedItem in <code>CHL2MP_Player::GiveDefaultItems</code>: | Add the following before the calls to GiveNamedItem in <code>CHL2MP_Player::GiveDefaultItems</code>: | ||
<code>m_bSpawning = true;</code> | |||
Add the following after the calls to GiveNamedItem in <code>CHL2MP_Player::GiveDefaultItems</code>: | Add the following after the calls to GiveNamedItem in <code>CHL2MP_Player::GiveDefaultItems</code>: | ||
===basecombatcharacter_shared.cpp== | <source lang=cpp>m_bSpawning = false;</source> | ||
==basecombatcharacter_shared.cpp== | |||
Remove the following from <code>CBaseCombatCharacter::Weapon_Switch</code>: | Remove the following from <code>CBaseCombatCharacter::Weapon_Switch</code>: | ||
m_hActiveWeapon = pWeapon; | m_hActiveWeapon = pWeapon; | ||
Add the following to <code>CBaseCombatCharacter::Weapon_CanSwitchTo</code>: | Add the following to <code>CBaseCombatCharacter::Weapon_CanSwitchTo</code>: | ||
===basecombatweapon_shared.cpp== | <source lang=cpp> if (pVehicle && !pPlayer->UsingStandardWeaponsInVehicle()) | ||
return false; | |||
#ifndef CLIENT_DLL | |||
if(pPlayer->IsSpawning()) | |||
return false; | |||
#endif | |||
}</source> | |||
==basecombatweapon_shared.cpp== | |||
Add the following system to this file to act as the timer for triggering the weapon deploy: | Add the following system to this file to act as the timer for triggering the weapon deploy: | ||
< | |||
<source lang=cpp>#ifdef CLIENT_DLL | |||
#define CShowWeapon C_ShowWeapon | #define CShowWeapon C_ShowWeapon | ||
#endif | #endif | ||
class CShowWeapon : public | class CShowWeapon : public CAutoGameSystemPerFrame | ||
{ | { | ||
public: | public: | ||
Line 114: | Line 131: | ||
float m_flTime; | float m_flTime; | ||
}; | }; | ||
static CShowWeapon g_ShowWeapon;</ | static CShowWeapon g_ShowWeapon;</source> | ||
---- | ---- | ||
Modify DefaultDeploy so it utilizes the new system: | Modify DefaultDeploy so it utilizes the new system: | ||
< | <source lang=cpp>bool CBaseCombatWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt ) | ||
{ | { | ||
// Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime ); | // Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime ); | ||
Line 150: | Line 167: | ||
return true; | return true; | ||
}</ | }</source> | ||
[[Category: | [[Category:Weapons programming]] | ||
[[Category:Tutorials]] |
Latest revision as of 17:54, 18 July 2025
This tutorial provides insight on giving an active weapon time to play its holster animation before showing a newly chosen weapon in the Half-Life 2 Deathmatch SDK. A new game system is introduced to the code so the switch is predicted on the client (which would only be needed in multiplayer). The code also prevents itself from being active when a player is being equipped when spawning.


c_basecombatcharacter.h
Add the following to the client combat character class:
friend class C_ShowWeapon; // This allows CShowWeapon to access whatever it needs to update for the character
basecombatcharacter.h
Add the following to the server combat character class:
friend class CShowWeapon; // This allows CShowWeapon to access whatever it needs to update for the character
player.h
Add the following to the player class:
public:
bool IsSpawning() { return m_bSpawning; }
protected:
bool m_bSpawning;
hl2mp_player.cpp
Add the following before the calls to GiveNamedItem in CHL2MP_Player::GiveDefaultItems
:
m_bSpawning = true;
Add the following after the calls to GiveNamedItem in CHL2MP_Player::GiveDefaultItems
:
m_bSpawning = false;
Remove the following from CBaseCombatCharacter::Weapon_Switch
:
m_hActiveWeapon = pWeapon;
Add the following to CBaseCombatCharacter::Weapon_CanSwitchTo
:
if (pVehicle && !pPlayer->UsingStandardWeaponsInVehicle())
return false;
#ifndef CLIENT_DLL
if(pPlayer->IsSpawning())
return false;
#endif
}
Add the following system to this file to act as the timer for triggering the weapon deploy:
#ifdef CLIENT_DLL
#define CShowWeapon C_ShowWeapon
#endif
class CShowWeapon : public CAutoGameSystemPerFrame
{
public:
bool Init()
{
ClearShowWeapon();
return true;
}
void FrameUpdatePreEntityThink()
{
if(m_pWeapon&&m_flTime<gpGlobals->curtime)
{
ShowWeapon();
}
}
void Update(float frametime)
{
FrameUpdatePreEntityThink(); // This adds compatibility to this gamesystem on the client
}
void SetShowWeapon(CBaseCombatWeapon *pWeapon, int iActivity, float delta)
{
m_pWeapon = pWeapon;
m_iActivity = iActivity;
if(delta==0)
{
ShowWeapon();
}
else
{
m_flTime = gpGlobals->curtime + delta;
}
}
void ClearShowWeapon()
{
m_pWeapon = NULL;
}
private:
void ShowWeapon()
{
Assert(m_pWeapon);
m_pWeapon->SetWeaponVisible(true);
if(m_pWeapon->GetOwner())
{
CBaseCombatWeapon *pLastWeapon = m_pWeapon->GetOwner()->GetActiveWeapon();
m_pWeapon->GetOwner()->m_hActiveWeapon = m_pWeapon;
CBasePlayer *pOwner = ToBasePlayer( m_pWeapon->GetOwner() );
if ( pOwner )
{
m_pWeapon->SetViewModel();
m_pWeapon->SendWeaponAnim( m_iActivity );
pOwner->SetNextAttack( gpGlobals->curtime + m_pWeapon->SequenceDuration() );
if ( pLastWeapon && pOwner->Weapon_ShouldSetLast( pLastWeapon, m_pWeapon ) )
{
pOwner->Weapon_SetLast( pLastWeapon->GetLastWeapon() );
}
CBaseViewModel *pViewModel = pOwner->GetViewModel();
Assert( pViewModel );
if ( pViewModel )
pViewModel->RemoveEffects( EF_NODRAW );
pOwner->ResetAutoaim( );
}
}
// Can't shoot again until we've finished deploying
m_pWeapon->m_flNextSecondaryAttack = m_pWeapon->m_flNextPrimaryAttack = gpGlobals->curtime + m_pWeapon->SequenceDuration();
ClearShowWeapon();
}
CBaseCombatWeapon *m_pWeapon;
int m_iActivity;
float m_flTime;
};
static CShowWeapon g_ShowWeapon;
Modify DefaultDeploy so it utilizes the new system:
bool CBaseCombatWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
{
// Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime );
// Weapons that don't autoswitch away when they run out of ammo
// can still be deployed when they have no ammo.
if ( !HasAnyAmmo() && AllowsAutoSwitchFrom() )
return false;
float flSequenceDuration = 0.0f;
if(GetOwner())
{
if ( !GetOwner()->IsAlive() )
return false;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner )
{
pOwner->SetAnimationExtension( szAnimExt );
}
CBaseCombatWeapon *pActive = GetOwner()->GetActiveWeapon();
if ( pActive && pActive->GetActivity() == ACT_VM_HOLSTER )
{
flSequenceDuration = pActive->SequenceDuration();
}
}
g_ShowWeapon.SetShowWeapon( this, iActivity, flSequenceDuration );
#ifndef CLIENT_DLL
// Cancel any pending hide events
g_EventQueue.CancelEventOn( this, "HideWeapon" );
#endif
return true;
}