Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Half-Life] Issues with weapon animations [Their Fixes Included] #2495

Open
BlackShadow opened this issue Jun 2, 2019 · 27 comments
Open

[Half-Life] Issues with weapon animations [Their Fixes Included] #2495

BlackShadow opened this issue Jun 2, 2019 · 27 comments

Comments

@BlackShadow
Copy link

BlackShadow commented Jun 2, 2019

Hi,

Some weapons animations can't and won't animate properly because there's not enough time given to them to play it or some of them are straight broken. I'll be listing these weapons with their fixes.

Side Note: These fixes won't effect gameplay in any way. These are just cosmetic fix. These fixes make game look more proper. Also HD models are compatiable with these fixes.

RPG: RPG's fidget animation can't animate properly because there's not enough time given to it.

To fix this:

Change:

               iAnim = RPG_FIDGET;
	  m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0;

To:

                iAnim = RPG_FIDGET;
           m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0;

Gauss: Gauss's idle animation's are completely broken. This issue appears to be in Steam version. Retail version seems to be working properly.

To fix this:

Change:

else
	{
		int iAnim;
		float flRand = RANDOM_FLOAT(0, 1);
		if (flRand <= 0.5)
		{
			iAnim = GAUSS_IDLE;
			m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
		}
		else if (flRand <= 0.75)
		{
			iAnim = GAUSS_IDLE2;
			m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
		}
		else
		{
			iAnim = GAUSS_FIDGET;
			m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
		}
		return;
		SendWeaponAnim( iAnim );
		
	}
}

To:

if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
		return;

	if (m_fInAttack != 0)
	{
		StartFire();
		m_fInAttack = 0;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0;
	}
	
	if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase())
		return;

	int iAnim;
	float flRand = UTIL_SharedRandomFloat(m_pPlayer->random_seed, 0, 1);
	if (flRand <= 0.75)
	{
		iAnim = GAUSS_IDLE;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 15.6 * (2);
	}
	else if (flRand <= 0.875)
	{
		iAnim = GAUSS_IDLE2;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 19.0;
	}
	else
	{
		iAnim = GAUSS_FIDGET;
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 85.0 / 15.0;
	}
	SendWeaponAnim(iAnim);
}

Hand Grenade: Hand Grenade is supposed to play HANDGRENADE_DRAW animation after player threw a grenade.

Commenting out "m_flReleaseThrow = 0;" fixes our issue. Thanks to @SamVanheer pointing this out.

	```
        //m_flReleaseThrow = 0;
	m_flStartThrow = 0;
	m_flNextPrimaryAttack = GetNextAttackDelay(0.5);
	m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
            ```

However after player ran out of grenades and pick up a grenade, it won't show up until player switch weapons.

We can easily fix this issue by removing " RetireWeapon(); "


if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] )
		{
			SendWeaponAnim( HANDGRENADE_DRAW );
		}
		else
		{
			RetireWeapon(); //Delete this
			return;
		}

Satchel and Snark (Squeak):

Satchel can't animate it's draw animation properly. This issue happens in Snark as well.

in weapons.cpp:

BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body )
{
	if (!CanDeploy( ))
		return FALSE;

	m_pPlayer->TabulateAmmo();
	m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel);
	m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
	strcpy( m_pPlayer->m_szAnimExtention, szAnimExt );
	SendWeaponAnim( iAnim, skiplocal, body );

	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
	m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; //Change 1.0 to 3.0
	m_flLastFireTime = 0.0;

	return TRUE;
}

This fixes draw animation problem. All i did was change, "m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0;" to "m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0;"

This gives enough time to play draw animation to these weapons.

@SamVanheer
Copy link

Be very careful when changing variables in weapons code, any change in timing could have unexpected side-effects.

@BlackShadow
Copy link
Author

@SamVanheer I can confirm these fixes are tested and doesn't break any weapons.

@ExpertPizzaTipper
Copy link

The crowbar never plays it's idle animations.

@CS-PRO1
Copy link

CS-PRO1 commented Jun 2, 2019

There's also the crowbar idle animations and the tripmines attaching animations (sequence names: arm1 and place)

@BlackShadow
Copy link
Author

BlackShadow commented Jun 3, 2019

@Don576 I'll look into that

@CS-PRO1 Those animations are beta animations, Valve dropped those animations during development.

More info : https://youtu.be/e59bvmvXPk0?t=202

@CS-PRO1
Copy link

CS-PRO1 commented Jun 3, 2019

They're still not cut tho. Maybe they were intended to be in the final one. Or maybe implement just "place" and drop "arm1"

@BlackShadow
Copy link
Author

BlackShadow commented Jun 3, 2019

@CS-PRO1 They're "leftover" from beta. These are common things in development. Devs became lazy or rush things and forgot delete those kinds of things. That's why they called "leftover".

@BlackShadow
Copy link
Author

I looked up idle animations of Crowbar and it seems Valve never implemented them. I don't really know if Valve dropped the idea during development or forgot adding them.

@CS-PRO1
Copy link

CS-PRO1 commented Jun 10, 2019

I looked up idle animations of Crowbar and it seems Valve never implemented them. I don't really know if Valve dropped the idea during development or forgot adding them.

I don't think so, in HL:S they work as intended.

@SamVanheer
Copy link

Note that the Crowbar doesn't have a WeaponIdle method at all, and the Source SDK handles it by using a common base class that looks up animations by act, so that could just be an unintentional side-effect rather than intended behavior.

@CS-PRO1
Copy link

CS-PRO1 commented Jun 10, 2019

I've seen SC had fixed Idle for crowbar but I dunno if it's possible to implement in HL tho.

@BlackShadow
Copy link
Author

It's possible, but they didn't added. As the Sam said they not even added WeaponIdle and this made me think straight away they cut the crowbar animations.

@OpenRift412
Copy link

OpenRift412 commented Mar 1, 2021

Gauss: Gauss's idle animation's are completely broken. This issue appears to be in Steam version. Retail version seems to be working properly.

I tested this in versions 1.0.1.6 and 1.0.0.5 (release build), and there didn't appear to be an idle animation for the Tau Cannon/Gauss. Perhaps this was an unused animation, like the one for the crowbar?

EDIT: Also checked version 1.1.1.0 of the WON (Retail) version, also doesn't appear to be present there either.

@BlackShadow
Copy link
Author

Gauss: Gauss's idle animation's are completely broken. This issue appears to be in Steam version. Retail version seems to be working properly.

I tested this in versions 1.0.1.6 and 1.0.0.5 (release build), and there didn't appear to be an idle animation for the Tau Cannon/Gauss. Perhaps this was an unused animation, like the one for the crowbar?

EDIT: Also checked version 1.1.1.0 of the WON (Retail) version, also doesn't appear to be present there either.

Judging from code Gauss's idle animations are intended because it has WeaponIdle. It doesn't work because of strings are missing.

@SamVanheer
Copy link

The Gauss's idle animations are disabled because there's a return statement before SendWeaponAnim:

halflife/dlls/gauss.cpp

Lines 568 to 590 in c7240b9

{
int iAnim;
float flRand = RANDOM_FLOAT(0, 1);
if (flRand <= 0.5)
{
iAnim = GAUSS_IDLE;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
else if (flRand <= 0.75)
{
iAnim = GAUSS_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
else
{
iAnim = GAUSS_FIDGET;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
}
return;
SendWeaponAnim( iAnim );
}

It's been like that since SDK 1.0 so it's probably intentional.

@BlackShadow
Copy link
Author

BlackShadow commented Mar 1, 2021

BUGBUGBUG - Only bug i could found with this fix is Shotgun continues to reload delayed when weapons switched during reload.

This happens because Shotgun's reload depends on m_flTimeWeaponIdle = UTIL_WeaponTimeBase()

And the reason why it's happens because we've changed m_flTimeWeaponIdle = UTIL_WeaponTimeBase() time to 3.0 from 1.0 And that makes Shotgun reload is a bit delayed. I've tried few things but i couldn't find a proper fix.

@OpenRift412
Copy link

BUGBUGBUG - Only bug i could found with this fix is Shotgun continues to reload delayed when weapons switched during reload.

This happens because Shotgun's reload depends on m_flTimeWeaponIdle = UTIL_WeaponTimeBase()

This is happens because we changed m_flTimeWeaponIdle = UTIL_WeaponTimeBase() time to 3.0 from 1.0 And that makes Shotgun reload is a bit delayed. I've tried few things to fix this but i couldn't fix a proper fix.

I did notice this as well. Hopefully someone finds a fix for this.

@SamVanheer
Copy link

BUGBUGBUG - Only bug i could found with this fix is Shotgun continues to reload delayed when weapons switched during reload.

This happens because Shotgun's reload depends on m_flTimeWeaponIdle = UTIL_WeaponTimeBase()

And the reason why it's happens because we've changed m_flTimeWeaponIdle = UTIL_WeaponTimeBase() time to 3.0 from 1.0 And that makes Shotgun reload is a bit delayed. I've tried few things but i couldn't find a proper fix.

My recommendation is to not change DefaultDeploy and instead changing the idle time separately in those weapons that need a different delay. That way other weapons are unaffected.

@OpenRift412
Copy link

BUGBUGBUG - Only bug i could found with this fix is Shotgun continues to reload delayed when weapons switched during reload.
This happens because Shotgun's reload depends on m_flTimeWeaponIdle = UTIL_WeaponTimeBase()
And the reason why it's happens because we've changed m_flTimeWeaponIdle = UTIL_WeaponTimeBase() time to 3.0 from 1.0 And that makes Shotgun reload is a bit delayed. I've tried few things but i couldn't find a proper fix.

My recommendation is to not change DefaultDeploy and instead changing the idle time separately in those weapons that need a different delay. That way other weapons are unaffected.

How would you do that? I'm new to this sorta stuff, so I wouldn't know.

@SamVanheer
Copy link

if (DefaultDeploy(stuff))
{
    m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0;
}

@OpenRift412
Copy link

if (DefaultDeploy(stuff))
{
    m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0;
}

What would I put in the place of "stuff"? Would I be replacing *szViewModel, *szWeaponModel, etc. with specific weapon names?

@SamVanheer
Copy link

Using the satchel as an example:

halflife/dlls/satchel.cpp

Lines 292 to 305 in c7240b9

BOOL CSatchel::Deploy( )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
if ( m_chargeReady )
return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" );
else
return DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" );
return TRUE;
}

Modify it to look like this:

BOOL CSatchel::Deploy( )
{

	m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
	//m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );

	BOOL result = FALSE;

	if ( m_chargeReady )
		result = DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" );
	else
		result = DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" );

	if (result)
	{
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
	}

	return result;
}

Note how i've commented out the first assignment since the value is overwritten anyway. I've also replaced the return statement on the last line since that line was never reached before.

Also keep in mind that some weapon functions are duplicated on the client side for prediction:

BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body )
{
if ( !CanDeploy() )
return FALSE;
gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel );
SendWeaponAnim( iAnim, skiplocal, body );
g_irunninggausspred = false;
m_pPlayer->m_flNextAttack = 0.5;
m_flTimeWeaponIdle = 1.0;
return TRUE;
}

If you modify the server side you also need to modify the client side so everything stays in sync.

@OpenRift412
Copy link

So then for the snark, it would change from this:

BOOL CSqueak::Deploy( )
{
// play hunt sound
float flRndSound = RANDOM_FLOAT ( 0 , 1 );

if ( flRndSound <= 0.5 )
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100);

m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;

return DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" );
}

To this?

BOOL CSqueak::Deploy( )
{
// play hunt sound
float flRndSound = RANDOM_FLOAT ( 0 , 1 );

if ( flRndSound <= 0.5 )
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100);
if (result)
{
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
}

m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;

return result;
}

Am I getting this right?

@SamVanheer
Copy link

No.

BOOL CSqueak::Deploy( )
{
	// play hunt sound
	float flRndSound = RANDOM_FLOAT ( 0 , 1 );

	if ( flRndSound <= 0.5 )
		EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100);
	else 
		EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100);

	m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;

	BOOL result = DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" );
	
	if (result)
	{
		m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
	}
	
	return result;
}

I'd suggest learning C++ before trying to figure stuff like this out, you really need to understand what's going on to fix stuff like this.

@OpenRift412
Copy link

I'd suggest learning C++ before trying to figure stuff like this out, you really need to understand what's going on to fix stuff like this.

I learn better by example. Thanks for the clarification though.

@SamVanheer
Copy link

A few notes:

  • The RPG fidget time should be 6.1 seconds to match the animation length
  • The satchel deploy time should be 2 seconds to match the animation length
  • The snark deploy time should be 1.7 seconds to match the animation length

Instead of commenting out RetireWeapon for the hand grenade the code for that should be changed to handle exhaustible weapons properly in general.

Modify this:

halflife/dlls/weapons.cpp

Lines 1182 to 1190 in c7240b9

void CBasePlayerWeapon::RetireWeapon( void )
{
// first, no viewmodel at all.
m_pPlayer->pev->viewmodel = iStringNull;
m_pPlayer->pev->weaponmodel = iStringNull;
//m_pPlayer->pev->viewmodelindex = NULL;
g_pGameRules->GetNextBestWeapon( m_pPlayer, this );
}

To include this:

void CBasePlayerWeapon::RetireWeapon()
{
	// first, no viewmodel at all.
	m_pPlayer->pev->viewmodel = iStringNull;
	m_pPlayer->pev->weaponmodel = iStringNull;
	//m_pPlayer->pev->viewmodelindex = NULL;

	g_pGameRules->GetNextBestWeapon( m_pPlayer, this );

	//If we're still equipped and we couldn't switch to another weapon, dequip this one
	if (CanHolster() && m_pPlayer->m_pActiveItem == this)
	{
		m_pPlayer->SwitchWeapon(nullptr);
	}
}

And modify this:

halflife/dlls/player.cpp

Lines 4648 to 4666 in c7240b9

BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon )
{
if ( !pWeapon->CanDeploy() )
{
return FALSE;
}
ResetAutoaim( );
if (m_pActiveItem)
{
m_pActiveItem->Holster( );
}
m_pActiveItem = pWeapon;
pWeapon->Deploy( );
return TRUE;
}

To include this:

BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) 
{
	if (pWeapon && !pWeapon->CanDeploy() )
	{
		return FALSE;
	}
	
	ResetAutoaim( );
	
	if (m_pActiveItem)
	{
		m_pActiveItem->Holster( );
	}

	m_pActiveItem = pWeapon;

	if (pWeapon)
	{
		pWeapon->Deploy();
	}

	return TRUE;
}

This allows switching to no weapon. When a weapon is retired, if the player still has it equipped after an attempted switch to next best weapon and the current weapon can be holstered the player's current weapon will be holstered.

If you then pick up ammo for that weapon it will be deployed as usual.

See also #3073 for a bug affecting Snark primary attack and #3069 for a bug that can cause the Snark's deploy animation to not play sometimes.

@mr-sihc
Copy link

mr-sihc commented Jun 5, 2021

@kisak-valve DONT FORGET DIS
and could someone open a pull request or something pls?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants