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.
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;
}