Closed LMS007 closed 11 years ago
related to #81
The problem is that most people use 100 FPS, so if this is changed the shooting rates must be recalculated for the current 100 FPS ones since they are by default probably calculated for 72 FPS.
It still does not force the same time for all fps's. The way it needs to be done is it needs to keep tract of the time that the last shot was fired then subtract the delay time (0.1 for the mp5) and find out the "creep" time.
For example: at 41fps each frame is 0.024 seconds long...
so at time 0 we fire
You can see the trend. The creep time is 0.02 for each shot. I was able to correct for creep time and subtract that from the next delay and I get the mp5 to fire its entire clip in 4.90 seconds for any FPS value which is the correct time. Its a lot of work to convert each of the weapons, but I'm going to move my code into weapons.cpp so the call should be minimal.
If the engine could detect what the creep time was for each client and then automatically subtract that from the next requested delay then we don't need to modify tons of files... But that may be tricky to do for all cases.
accruing the slop seems reasonable @LMS007 , if you post some code I can look at applying it.
Sorry, just edited my example, i did had the reciprocal of the fps :) fixed it now. Alfred, when i get home I'll post the code tonight, btw, off topic, but how do i opt in for the beta? sorry for being such a nub :)
~I don't know how to turn off the mark down... so pretend this unified patch file.~
+++
@@ -992,12 +992,13 @@
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;
- m_flLastFireTime = 0.0;
return TRUE;
}
BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body )
@@ -1054,12 +1055,41 @@
void CBasePlayerWeapon::Holster( int skiplocal /\* = 0 */ )
{
m_fInReload = FALSE; // cancel any reload in progress.
m_pPlayer->pev->viewmodel = 0;
m_pPlayer->pev->weaponmodel = 0;
}
+
+//=========================================================================
+// GetNextAttackDelay - An accurate way of calcualting the next attack time.
+//=========================================================================
+float CBasePlayerWeapon::GetNextAttackDelay( float delay ) {
-
- if(m_flLastFireTime == 0 || m_flNextPrimaryAttack == -1)
- {
- // At this point, we are assuming that the client has stopped firing
- // and we are going to reset our book keeping variables.
- m_flLastFireTime = gpGlobals->time;
- m_flPrevPrimaryAttack = delay;
- }
- // calculate the time between this shot and the previous
- float flTimeBetweenFires = gpGlobals->time - m_flLastFireTime;
- float flCreep = 0.0f;
- if(flTimeBetweenFires > 0)
- flCreep = flTimeBetweenFires - m_flPrevPrimaryAttack; // postive or negative
+
- // save the last fire time
- m_flLastFireTime = gpGlobals->time;
+
- float flNextAttack = UTIL_WeaponTimeBase() + delay - flCreep;
- // we need to remember what the m_flNextPrimaryAttack time is set to for each shot,
- // store it as m_flPrevPrimaryAttack.
- m_flPrevPrimaryAttack = flNextAttack;
- return flNextAttack;
+}
+
void CBasePlayerAmmo::Spawn( void )
{
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16));
+++
@@ -328,21 +328,27 @@
virtual void WeaponIdle( void ) { return; } // called when no buttons pressed
virtual int UpdateClientData( CBasePlayer *pPlayer ); // sends hud info to client dll, if things have changed
virtual void RetireWeapon( void );
virtual BOOL ShouldWeaponIdle( void ) {return FALSE; };
virtual void Holster( int skiplocal = 0 );
virtual BOOL UseDecrement( void ) { return FALSE; };
- virtual float GetNextAttackDelay( float ); // use this to get an accurate attack delay that accounts for time creep
int PrimaryAmmoIndex();
int SecondaryAmmoIndex();
void PrintState( void );
virtual CBasePlayerItem *GetWeaponPtr( void ) { return (CBasePlayerItem *)this; };
float m_flPumpTime;
+
- // hle time creep vars
- float m_flPrevPrimaryAttack;
- float m_flLastFireTime;
+
int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns
float m_flNextPrimaryAttack; // soonest time ItemPostFrame will call PrimaryAttack
float m_flNextSecondaryAttack; // soonest time ItemPostFrame will call SecondaryAttack
float m_flTimeWeaponIdle; // soonest time ItemPostFrame will call WeaponIdle
int m_iPrimaryAmmoType; // "primary" ammo index into players m_rgAmmo[]
int m_iSecondaryAmmoType; // "secondary" ammo index into players m_rgAmmo[]
+++
@@ -182,14 +182,15 @@
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 );
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
## \- m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
- // m_flNextPrimaryAttack is adjusted for time creep
- m_flNextPrimaryAttack = GetNextAttackDelay(0.1);
- if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() )
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
And you need to hook up a dummy method on the client so it links. The return value doesn't really matter
I'll try just posting the main part of the code
//=========================================================================
// GetNextAttackDelay - An accurate way of calcualting the next attack time.
//=========================================================================
float CBasePlayerWeapon::GetNextAttackDelay( float delay ) {
if(m_flLastFireTime == 0 || m_flNextPrimaryAttack == -1)
{
// At this point, we are assuming that the client has stopped firing
// and we are going to reset our book keeping variables.
m_flLastFireTime = gpGlobals->time;
m_flPrevPrimaryAttack = delay;
}
// calculate the time between this shot and the previous
float flTimeBetweenFires = gpGlobals->time - m_flLastFireTime;
float flCreep = 0.0f;
if(flTimeBetweenFires > 0)
flCreep = flTimeBetweenFires - m_flPrevPrimaryAttack; // postive or negative
// save the last fire time
m_flLastFireTime = gpGlobals->time;
float flNextAttack = UTIL_WeaponTimeBase() + delay - flCreep;
// we need to remember what the m_flNextPrimaryAttack time is set to for each shot,
// store it as m_flPrevPrimaryAttack.
m_flPrevPrimaryAttack = flNextAttack;
return flNextAttack;
}
Then add
m_flLastFireTime = 0.0;
inside of DefaultDeploy() or somewhere where it can be set to 0 initially.
try to paste your code into <_pre_></pre> without * ;)
jfyi, https://gist.github.com/ is really handy for chunks of code :)
@LMS007 to opt into the beta you need to have both hl1 and cs 1.6. You have to also have both of them fully installed and updated. Then you right click on them in the steam library, click properties, then the beta tab.
I've reverted this change for CS 1.6, this doesn't behave well for it (it causes stuttering during firing).
Could this bug still be fixed with a fix for the stuttering?
If that can be worked out, for now I haven't found the root cause.
Half-Life also has bug with stuttering.
In Half-Life 1 try to shoot with 100 fps and then with 250 fps (9mmAR/MP5)
Depends on the FPS, but if the weapon delay lines up poorly with the next frame then there is an time creep on the shot. This creep can be as much as 30 milliseconds which will make the MP5 (for example) shoot a full ~33% slower.
This has been a problem since the first version and continues in the new patch.... I suspect counterstrike & TFC have this same issue, but I have not tested it.